diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs
index 162828ee80b..b63f51138c3 100644
--- a/compiler/rustc_borrowck/src/type_check/mod.rs
+++ b/compiler/rustc_borrowck/src/type_check/mod.rs
@@ -26,6 +26,7 @@ use rustc_middle::mir::tcx::PlaceTy;
 use rustc_middle::mir::visit::{NonMutatingUseContext, PlaceContext, Visitor};
 use rustc_middle::mir::AssertKind;
 use rustc_middle::mir::*;
+use rustc_middle::traits::ObligationCause;
 use rustc_middle::ty::adjustment::PointerCast;
 use rustc_middle::ty::cast::CastTy;
 use rustc_middle::ty::subst::{SubstsRef, UserSubsts};
@@ -48,6 +49,7 @@ use rustc_mir_dataflow::impls::MaybeInitializedPlaces;
 use rustc_mir_dataflow::move_paths::MoveData;
 use rustc_mir_dataflow::ResultsCursor;
 
+use crate::renumber::RegionCtxt;
 use crate::session_diagnostics::MoveUnsized;
 use crate::{
     borrow_set::BorrowSet,
@@ -183,6 +185,15 @@ pub(crate) fn type_check<'mir, 'tcx>(
         &mut borrowck_context,
     );
 
+    // FIXME(-Ztrait-solver=next): A bit dubious that we're only registering
+    // predefined opaques in the typeck root.
+    // FIXME(-Ztrait-solver=next): This is also totally wrong for TAITs, since
+    // the HIR typeck map defining usages back to their definition params,
+    // they won't actually match up with the usages in this body...
+    if infcx.tcx.trait_solver_next() && !infcx.tcx.is_typeck_child(body.source.def_id()) {
+        checker.register_predefined_opaques_in_new_solver();
+    }
+
     let mut verifier = TypeVerifier::new(&mut checker, promoted);
     verifier.visit_body(&body);
 
@@ -1023,6 +1034,57 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
         checker
     }
 
+    pub(super) fn register_predefined_opaques_in_new_solver(&mut self) {
+        // OK to use the identity substitutions for each opaque type key, since
+        // we remap opaques from HIR typeck back to their definition params.
+        let opaques: Vec<_> = self
+            .infcx
+            .tcx
+            .typeck(self.body.source.def_id().expect_local())
+            .concrete_opaque_types
+            .iter()
+            .map(|(&def_id, &hidden_ty)| {
+                let substs = ty::InternalSubsts::identity_for_item(self.infcx.tcx, def_id);
+                (ty::OpaqueTypeKey { def_id, substs }, hidden_ty)
+            })
+            .collect();
+
+        let renumbered_opaques = self.infcx.tcx.fold_regions(opaques, |_, _| {
+            self.infcx.next_nll_region_var(
+                NllRegionVariableOrigin::Existential { from_forall: false },
+                || RegionCtxt::Unknown,
+            )
+        });
+
+        let param_env = self.param_env;
+        let result = self.fully_perform_op(
+            Locations::All(self.body.span),
+            ConstraintCategory::OpaqueType,
+            CustomTypeOp::new(
+                |ocx| {
+                    for (key, hidden_ty) in renumbered_opaques {
+                        ocx.register_infer_ok_obligations(
+                            ocx.infcx.register_hidden_type_in_new_solver(
+                                key,
+                                param_env,
+                                hidden_ty.ty,
+                            )?,
+                        );
+                    }
+                    Ok(())
+                },
+                "register pre-defined opaques",
+            ),
+        );
+
+        if result.is_err() {
+            self.infcx.tcx.sess.delay_span_bug(
+                self.body.span,
+                "failed re-defining predefined opaques in mir typeck",
+            );
+        }
+    }
+
     fn body(&self) -> &Body<'tcx> {
         self.body
     }
diff --git a/compiler/rustc_trait_selection/src/solve/mod.rs b/compiler/rustc_trait_selection/src/solve/mod.rs
index 1427268f829..26ace28f5fd 100644
--- a/compiler/rustc_trait_selection/src/solve/mod.rs
+++ b/compiler/rustc_trait_selection/src/solve/mod.rs
@@ -239,34 +239,34 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
                     evaluate_normalizes_to(self, alias_rhs, lhs, direction, Invert::Yes).ok(),
                 );
                 // Relate via substs
-                candidates.extend(
-                    self.probe(|ecx| {
-                        let span = tracing::span!(
-                            tracing::Level::DEBUG,
-                            "compute_alias_relate_goal(relate_via_substs)",
-                            ?alias_lhs,
-                            ?alias_rhs,
-                            ?direction
-                        );
-                        let _enter = span.enter();
+                let subst_relate_response = self.probe(|ecx| {
+                    let span = tracing::span!(
+                        tracing::Level::DEBUG,
+                        "compute_alias_relate_goal(relate_via_substs)",
+                        ?alias_lhs,
+                        ?alias_rhs,
+                        ?direction
+                    );
+                    let _enter = span.enter();
 
-                        match direction {
-                            ty::AliasRelationDirection::Equate => {
-                                ecx.eq(goal.param_env, alias_lhs, alias_rhs)?;
-                            }
-                            ty::AliasRelationDirection::Subtype => {
-                                ecx.sub(goal.param_env, alias_lhs, alias_rhs)?;
-                            }
+                    match direction {
+                        ty::AliasRelationDirection::Equate => {
+                            ecx.eq(goal.param_env, alias_lhs, alias_rhs)?;
                         }
+                        ty::AliasRelationDirection::Subtype => {
+                            ecx.sub(goal.param_env, alias_lhs, alias_rhs)?;
+                        }
+                    }
 
-                        ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
-                    })
-                    .ok(),
-                );
+                    ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
+                });
+                candidates.extend(subst_relate_response);
                 debug!(?candidates);
 
                 if let Some(merged) = self.try_merge_responses(&candidates) {
                     Ok(merged)
+                } else if let Ok(subst_relate_response) = subst_relate_response {
+                    Ok(subst_relate_response)
                 } else {
                     self.flounder(&candidates)
                 }
diff --git a/compiler/rustc_trait_selection/src/solve/opaques.rs b/compiler/rustc_trait_selection/src/solve/opaques.rs
index 1d5bb46450c..f97f54e760e 100644
--- a/compiler/rustc_trait_selection/src/solve/opaques.rs
+++ b/compiler/rustc_trait_selection/src/solve/opaques.rs
@@ -1,6 +1,6 @@
 use rustc_middle::traits::query::NoSolution;
 use rustc_middle::traits::solve::{Certainty, Goal, QueryResult};
-use rustc_middle::traits::{ObligationCause, Reveal};
+use rustc_middle::traits::Reveal;
 use rustc_middle::ty;
 use rustc_middle::ty::util::NotUniqueParam;
 
@@ -37,11 +37,8 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
                         Ok(()) => {}
                     }
                     // Prefer opaques registered already.
-                    let matches = self.unify_existing_opaque_tys(
-                        goal.param_env,
-                        opaque_ty,
-                        expected
-                    );
+                    let matches =
+                        self.unify_existing_opaque_tys(goal.param_env, opaque_ty, expected);
                     if !matches.is_empty() {
                         if let Some(response) = self.try_merge_responses(&matches) {
                             return Ok(response);