diff --git a/django/db/models/query.py b/django/db/models/query.py
index f266e2bf22..7302a1dfee 100644
--- a/django/db/models/query.py
+++ b/django/db/models/query.py
@@ -1099,14 +1099,16 @@ class QuerySet:
         for field, objects in other._known_related_objects.items():
             self._known_related_objects.setdefault(field, {}).update(objects)
 
-    def _prepare_as_filter_value(self):
+    def resolve_expression(self, *args, **kwargs):
         if self._fields and len(self._fields) > 1:
             # values() queryset can only be used as nested queries
             # if they are set up to select only a single field.
             if len(self._fields) > 1:
                 raise TypeError('Cannot use multi-field values as a filter value.')
-        queryset = self._clone()
-        return queryset.query.as_subquery_filter(queryset._db)
+        query = self.query.resolve_expression(*args, **kwargs)
+        query._db = self._db
+        return query
+    resolve_expression.queryset_only = True
 
     def _add_hints(self, **hints):
         """
diff --git a/django/db/models/sql/query.py b/django/db/models/sql/query.py
index 8c3ed06040..5c3eca0032 100644
--- a/django/db/models/sql/query.py
+++ b/django/db/models/sql/query.py
@@ -976,8 +976,18 @@ class Query:
         self.append_annotation_mask([alias])
         self.annotations[alias] = annotation
 
-    def _prepare_as_filter_value(self):
-        return self.clone()
+    def resolve_expression(self, query, *args, **kwargs):
+        clone = self.clone()
+        # Subqueries need to use a different set of aliases than the outer query.
+        clone.bump_prefix(query)
+        clone.subquery = True
+        # It's safe to drop ordering if the queryset isn't using slicing,
+        # distinct(*fields) or select_for_update().
+        if (self.low_mark == 0 and self.high_mark is None and
+                not self.distinct_fields and
+                not self.select_for_update):
+            clone.clear_ordering(True)
+        return clone
 
     def prepare_lookup_value(self, value, lookups, can_reuse, allow_joins=True):
         # Default lookup if none given is exact.
@@ -1008,12 +1018,6 @@ class Query:
                     # The used_joins for a tuple of expressions is the union of
                     # the used_joins for the individual expressions.
                     used_joins |= set(k for k, v in self.alias_refcount.items() if v > pre_joins.get(k, 0))
-        # Subqueries need to use a different set of aliases than the
-        # outer query. Call bump_prefix to change aliases of the inner
-        # query (the value).
-        if hasattr(value, '_prepare_as_filter_value'):
-            value = value._prepare_as_filter_value()
-            value.bump_prefix(self)
         # For Oracle '' is equivalent to null. The check needs to be done
         # at this stage because join promotion can't be done at compiler
         # stage. Using DEFAULT_DB_ALIAS isn't nice, but it is the best we
@@ -1981,17 +1985,6 @@ class Query:
         else:
             return field.null
 
-    def as_subquery_filter(self, db):
-        self._db = db
-        self.subquery = True
-        # It's safe to drop ordering if the queryset isn't using slicing,
-        # distinct(*fields) or select_for_update().
-        if (self.low_mark == 0 and self.high_mark is None and
-                not self.distinct_fields and
-                not self.select_for_update):
-            self.clear_ordering(True)
-        return self
-
 
 def get_order_dir(field, default='ASC'):
     """