diff --git a/clang/lib/Driver/Driver.cpp b/clang/lib/Driver/Driver.cpp
--- a/clang/lib/Driver/Driver.cpp
+++ b/clang/lib/Driver/Driver.cpp
@@ -489,15 +489,15 @@
 ///
 /// This routine provides the logic to compute a target triple from various
 /// args passed to the driver and the default triple string.
-static llvm::Triple computeTargetTriple(const Driver &D,
-                                        StringRef TargetTriple,
-                                        const ArgList &Args,
-                                        StringRef DarwinArchName = "") {
+static llvm::Triple computeTargetTriple(
+    const Driver &D, StringRef TargetTriple, const ArgList &Args,
+    llvm::Triple *UnnormalizedTriple = nullptr, StringRef DarwinArchName = "") {
   // FIXME: Already done in Compilation *Driver::BuildCompilation
   if (const Arg *A = Args.getLastArg(options::OPT_target))
     TargetTriple = A->getValue();
 
   llvm::Triple Target(llvm::Triple::normalize(TargetTriple));
+  llvm::Triple Unnormalized(TargetTriple);
 
   // GNU/Hurd's triples should have been -hurd-gnu*, but were historically made
   // -gnu* only, and we can not change this, so we have to detect that case as
@@ -560,6 +560,14 @@
     }
   }
 
+  // llvm-project's runtime libraries support a small subset of GCC multilib
+  // combinations, currently just -m32/-m64. Transform the unnormalized triple
+  // to construct include and library paths.
+  auto SetArch = [&](llvm::Triple::ArchType Type) {
+    Target.setArch(Type);
+    Unnormalized.setArch(Type);
+  };
+
   // Handle pseudo-target flags '-m64', '-mx32', '-m32' and '-m16'.
   Arg *A = Args.getLastArg(options::OPT_m64, options::OPT_mx32,
                            options::OPT_m32, options::OPT_m16);
@@ -592,7 +600,7 @@
     }
 
     if (AT != llvm::Triple::UnknownArch && AT != Target.getArch()) {
-      Target.setArch(AT);
+      SetArch(AT);
       if (Target.isWindowsGNUEnvironment())
         toolchains::MinGW::fixTripleArch(D, Target, Args);
     }
@@ -651,6 +659,9 @@
       Target.setArch(llvm::Triple::riscv64);
   }
 
+  if (UnnormalizedTriple)
+    *UnnormalizedTriple = Unnormalized;
+
   return Target;
 }
 
@@ -1247,9 +1258,18 @@
   // Perform the default argument translations.
   DerivedArgList *TranslatedArgs = TranslateInputArgs(*UArgs);
 
+  // Unnormalized is --target= or LLVM_DEFAULT_TARGET_TRIPLE, with a small set
+  // of Clang specific multilib transformation.
+  llvm::Triple Unnormalized;
+  const llvm::Triple Normalized =
+      computeTargetTriple(*this, TargetTriple, *UArgs, &Unnormalized);
+  // Fuchsia prefers to use normalized triples.
+  if (Normalized.isOSFuchsia())
+    TargetTriple = Normalized.str();
+  else
+    TargetTriple = Unnormalized.str();
   // Owned by the host.
-  const ToolChain &TC = getToolChain(
-      *UArgs, computeTargetTriple(*this, TargetTriple, *UArgs));
+  const ToolChain &TC = getToolChain(*UArgs, Normalized);
 
   // The compilation takes ownership of Args.
   Compilation *C = new Compilation(*this, TC, UArgs.release(), TranslatedArgs,
@@ -4856,8 +4876,8 @@
 
     if (!ArchName.empty())
       TC = &getToolChain(C.getArgs(),
-                         computeTargetTriple(*this, TargetTriple,
-                                             C.getArgs(), ArchName));
+                         computeTargetTriple(*this, TargetTriple, C.getArgs(),
+                                             nullptr, ArchName));
     else
       TC = &C.getDefaultToolChain();
 
diff --git a/clang/lib/Driver/ToolChain.cpp b/clang/lib/Driver/ToolChain.cpp
--- a/clang/lib/Driver/ToolChain.cpp
+++ b/clang/lib/Driver/ToolChain.cpp
@@ -498,13 +498,20 @@
 
 ToolChain::path_list ToolChain::getRuntimePaths() const {
   path_list Paths;
-  auto addPathForTriple = [this, &Paths](const llvm::Triple &Triple) {
+  auto addPathForTriple = [this, &Paths](const std::string &TripleStr) {
     SmallString<128> P(D.ResourceDir);
-    llvm::sys::path::append(P, "lib", Triple.str());
+    llvm::sys::path::append(P, "lib", TripleStr);
     Paths.push_back(std::string(P.str()));
   };
 
-  addPathForTriple(getTriple());
+  // Prefer unnormalized D.getTargetTriple() (from --target= or
+  // LLVM_DEFAULT_TARGET_TRIPLE, with a small set of Clang specific multilib
+  // transformation).
+  addPathForTriple(D.getTargetTriple());
+  // Add the normalized triple as fallback. This is a hack for
+  // --target=x86_64-linux-gnu to pick up the x86_64-unknown-linux-gnu runtime
+  // path. TODO remove the hack when the user migrates away.
+  addPathForTriple(Triple.str());
 
   // Android targets may include an API level at the end. We still want to fall
   // back on a path without the API level.
@@ -512,7 +519,7 @@
       getTriple().getEnvironmentName() != "android") {
     llvm::Triple TripleWithoutLevel = getTriple();
     TripleWithoutLevel.setEnvironmentName("android");
-    addPathForTriple(TripleWithoutLevel);
+    addPathForTriple(TripleWithoutLevel.str());
   }
 
   return Paths;
@@ -521,9 +528,14 @@
 ToolChain::path_list ToolChain::getStdlibPaths() const {
   path_list Paths;
   SmallString<128> P(D.Dir);
-  llvm::sys::path::append(P, "..", "lib", getTripleString());
+  llvm::sys::path::append(P, "..", "lib", D.getTargetTriple());
   Paths.push_back(std::string(P.str()));
 
+  // Add the normalized triple as fallback. TODO remove the hack.
+  P = D.Dir;
+  llvm::sys::path::append(P, "..", "lib", Triple.str());
+  Paths.push_back(std::string(P));
+
   return Paths;
 }
 
diff --git a/clang/lib/Driver/ToolChains/Gnu.cpp b/clang/lib/Driver/ToolChains/Gnu.cpp
--- a/clang/lib/Driver/ToolChains/Gnu.cpp
+++ b/clang/lib/Driver/ToolChains/Gnu.cpp
@@ -2904,10 +2904,18 @@
       return false;
 
     // First add the per-target include path if it exists.
-    std::string TargetDir = Path + "/" + Target + "/c++/" + Version;
+    std::string TargetDir =
+        Path + "/" + D.getTargetTriple() + "/c++/" + Version;
     if (D.getVFS().exists(TargetDir))
       addSystemInclude(DriverArgs, CC1Args, TargetDir);
 
+    // Add the normalized triple as fallback. TODO remove the hack.
+    if (D.getTargetTriple() != Target) {
+      std::string NormalizedTargetDir = Path + "/" + Target + "/c++/" + Version;
+      if (D.getVFS().exists(NormalizedTargetDir))
+        addSystemInclude(DriverArgs, CC1Args, NormalizedTargetDir);
+    }
+
     // Second add the generic one.
     addSystemInclude(DriverArgs, CC1Args, Path + "/c++/" + Version);
     return true;
diff --git a/clang/test/Driver/Inputs/debian_per_target_tree/usr/lib/llvm-14/lib/x86_64-linux-gnu/.keep b/clang/test/Driver/Inputs/debian_per_target_tree/usr/lib/llvm-14/lib/x86_64-linux-gnu/.keep
new file mode 100644
diff --git a/clang/test/Driver/Inputs/debian_per_target_unknown_tree/usr/lib/llvm-14/bin/.keep b/clang/test/Driver/Inputs/debian_per_target_unknown_tree/usr/lib/llvm-14/bin/.keep
new file mode 100644
diff --git a/clang/test/Driver/Inputs/debian_per_target_unknown_tree/usr/lib/llvm-14/include/c++/v1/.keep b/clang/test/Driver/Inputs/debian_per_target_unknown_tree/usr/lib/llvm-14/include/c++/v1/.keep
new file mode 100644
diff --git a/clang/test/Driver/Inputs/debian_per_target_unknown_tree/usr/lib/llvm-14/include/i386-unknown-linux-gnu/c++/v1/.keep b/clang/test/Driver/Inputs/debian_per_target_unknown_tree/usr/lib/llvm-14/include/i386-unknown-linux-gnu/c++/v1/.keep
new file mode 100644
diff --git a/clang/test/Driver/Inputs/debian_per_target_unknown_tree/usr/lib/llvm-14/include/x86_64-unknown-linux-gnu/c++/v1/.keep b/clang/test/Driver/Inputs/debian_per_target_unknown_tree/usr/lib/llvm-14/include/x86_64-unknown-linux-gnu/c++/v1/.keep
new file mode 100644
diff --git a/clang/test/Driver/Inputs/debian_per_target_unknown_tree/usr/lib/llvm-14/lib/clang/14.0.0/lib/i386-unknown-linux-gnu/libclang_rt.builtins.a b/clang/test/Driver/Inputs/debian_per_target_unknown_tree/usr/lib/llvm-14/lib/clang/14.0.0/lib/i386-unknown-linux-gnu/libclang_rt.builtins.a
new file mode 100644
diff --git a/clang/test/Driver/Inputs/debian_per_target_unknown_tree/usr/lib/llvm-14/lib/clang/14.0.0/lib/x86_64-unknown-linux-gnu/libclang_rt.builtins.a b/clang/test/Driver/Inputs/debian_per_target_unknown_tree/usr/lib/llvm-14/lib/clang/14.0.0/lib/x86_64-unknown-linux-gnu/libclang_rt.builtins.a
new file mode 100644
diff --git a/clang/test/Driver/Inputs/debian_per_target_unknown_tree/usr/lib/llvm-14/lib/i386-unknown-linux-gnu/.keep b/clang/test/Driver/Inputs/debian_per_target_unknown_tree/usr/lib/llvm-14/lib/i386-unknown-linux-gnu/.keep
new file mode 100644
diff --git a/clang/test/Driver/Inputs/debian_per_target_unknown_tree/usr/lib/llvm-14/lib/x86_64-unknown-linux-gnu/.keep b/clang/test/Driver/Inputs/debian_per_target_unknown_tree/usr/lib/llvm-14/lib/x86_64-unknown-linux-gnu/.keep
new file mode 100644
diff --git a/clang/test/Driver/linux-cross.cpp b/clang/test/Driver/linux-cross.cpp
--- a/clang/test/Driver/linux-cross.cpp
+++ b/clang/test/Driver/linux-cross.cpp
@@ -152,19 +152,20 @@
 // DEBIAN_AARCH64-SAME: {{^}} "-L[[SYSROOT]]/usr/lib"
 
 /// Test native x86-64 with -DLLVM_ENABLE_PER_TARGET_RUNTIME_DIR=on.
-/// FIXME -internal-isystem .*bin/../include/x86_64-linux-gnu/c++/v1 and -L[[PREFIX]]/bin/../lib/x86_64-linux-gnu are missing.
 // RUN: %clang -### %s --target=x86_64-linux-gnu --sysroot=%S/Inputs/debian_multiarch_tree \
 // RUN:   -ccc-install-dir %S/Inputs/debian_per_target_tree/usr/lib/llvm-14/bin -resource-dir=%S/Inputs/debian_per_target_tree/usr/lib/llvm-14/lib/clang/14.0.0 \
 // RUN:   --stdlib=libc++ --rtlib=compiler-rt 2>&1 | FileCheck %s --check-prefix=DEBIAN_X86_64_PER_TARGET
 // DEBIAN_X86_64_PER_TARGET:      "-resource-dir" "[[RESOURCE:[^"]+]]"
 // DEBIAN_X86_64_PER_TARGET:      "-internal-isystem"
-// DEBIAN_X86_64_PER_TARGET-SAME: {{^}} "[[PREFIX:[^"]+llvm-14]]/bin/../include/c++/v1"
+// DEBIAN_X86_64_PER_TARGET-SAME: {{^}} "[[PREFIX:[^"]+llvm-14]]/bin/../include/x86_64-linux-gnu/c++/v1"
+// DEBIAN_X86_64_PER_TARGET-SAME: {{^}} "-internal-isystem" "[[PREFIX]]/bin/../include/c++/v1"
 // DEBIAN_X86_64_PER_TARGET-SAME: {{^}} "-internal-isystem" "[[RESOURCE]]/include"
 // DEBIAN_X86_64_PER_TARGET-SAME: {{^}} "-internal-isystem" "[[SYSROOT:[^"]+]]/usr/local/include"
 // DEBIAN_X86_64_PER_TARGET-SAME: {{^}} "-internal-isystem" "[[SYSROOT]]/usr/lib/gcc/x86_64-linux-gnu/10/../../../../x86_64-linux-gnu/include"
 
 // DEBIAN_X86_64_PER_TARGET:      "-L
-// DEBIAN_X86_64_PER_TARGET-SAME: {{^}}[[SYSROOT]]/usr/lib/gcc/x86_64-linux-gnu/10"
+// DEBIAN_X86_64_PER_TARGET-SAME: {{^}}[[PREFIX]]/bin/../lib/x86_64-linux-gnu"
+// DEBIAN_X86_64_PER_TARGET-SAME: {{^}} "-L[[SYSROOT]]/usr/lib/gcc/x86_64-linux-gnu/10"
 /// Debian patches MULTILIB_OSDIRNAMES (../lib64 -> ../lib), so gcc uses 'lib' instead of 'lib64'.
 /// This difference does not matter in practice.
 // DEBIAN_X86_64_PER_TARGET-SAME: {{^}} "-L[[SYSROOT]]/usr/lib/gcc/x86_64-linux-gnu/10/../../../../lib64"
@@ -177,21 +178,53 @@
 /// $sysroot/lib and $sysroot/usr/lib. Fallback when GCC installation is unavailable.
 // DEBIAN_X86_64_PER_TARGET-SAME: {{^}} "-L[[SYSROOT]]/lib"
 // DEBIAN_X86_64_PER_TARGET-SAME: {{^}} "-L[[SYSROOT]]/usr/lib"
+// DEBIAN_X86_64_PER_TARGET-SAME: "[[RESOURCE]]/lib/x86_64-linux-gnu/libclang_rt.builtins.a"
+
+/// A variant of the above where the hierarchy uses x86_64-unknown-linux-gnu where --target= is unnormalized.
+/// This is a hack for --target=x86_64-linux-gnu to pick up the x86_64-unknown-linux-gnu include/library path.
+// RUN: %clang -### %s --target=x86_64-linux-gnu --sysroot=%S/Inputs/debian_multiarch_tree \
+// RUN:   -ccc-install-dir %S/Inputs/debian_per_target_unknown_tree/usr/lib/llvm-14/bin -resource-dir=%S/Inputs/debian_per_target_unknown_tree/usr/lib/llvm-14/lib/clang/14.0.0 \
+// RUN:   --stdlib=libc++ --rtlib=compiler-rt 2>&1 | FileCheck %s --check-prefix=DEBIAN_X86_64_PER_TARGET_UNKNOWN
+// DEBIAN_X86_64_PER_TARGET_UNKNOWN:      "-resource-dir" "[[RESOURCE:[^"]+]]"
+// DEBIAN_X86_64_PER_TARGET_UNKNOWN:      "-internal-isystem"
+// DEBIAN_X86_64_PER_TARGET_UNKNOWN-SAME: {{^}} "[[PREFIX:[^"]+llvm-14]]/bin/../include/x86_64-unknown-linux-gnu/c++/v1"
+// DEBIAN_X86_64_PER_TARGET_UNKNOWN-SAME: {{^}} "-internal-isystem" "[[PREFIX]]/bin/../include/c++/v1"
+// DEBIAN_X86_64_PER_TARGET_UNKNOWN-SAME: {{^}} "-internal-isystem" "[[RESOURCE]]/include"
+// DEBIAN_X86_64_PER_TARGET_UNKNOWN-SAME: {{^}} "-internal-isystem" "[[SYSROOT:[^"]+]]/usr/local/include"
+// DEBIAN_X86_64_PER_TARGET_UNKNOWN-SAME: {{^}} "-internal-isystem" "[[SYSROOT]]/usr/lib/gcc/x86_64-linux-gnu/10/../../../../x86_64-linux-gnu/include"
+
+// DEBIAN_X86_64_PER_TARGET_UNKNOWN:      "-L
+// DEBIAN_X86_64_PER_TARGET_UNKNOWN-SAME: {{^}}[[PREFIX]]/bin/../lib/x86_64-unknown-linux-gnu"
+// DEBIAN_X86_64_PER_TARGET_UNKNOWN-SAME: {{^}} "-L[[SYSROOT]]/usr/lib/gcc/x86_64-linux-gnu/10"
+/// Debian patches MULTILIB_OSDIRNAMES (../lib64 -> ../lib), so gcc uses 'lib' instead of 'lib64'.
+/// This difference does not matter in practice.
+// DEBIAN_X86_64_PER_TARGET_UNKNOWN-SAME: {{^}} "-L[[SYSROOT]]/usr/lib/gcc/x86_64-linux-gnu/10/../../../../lib64"
+// DEBIAN_X86_64_PER_TARGET_UNKNOWN-SAME: {{^}} "-L[[SYSROOT]]/lib/x86_64-linux-gnu"
+// DEBIAN_X86_64_PER_TARGET_UNKNOWN-SAME: {{^}} "-L[[SYSROOT]]/lib/../lib64"
+// DEBIAN_X86_64_PER_TARGET_UNKNOWN-SAME: {{^}} "-L[[SYSROOT]]/usr/lib/x86_64-linux-gnu"
+// DEBIAN_X86_64_PER_TARGET_UNKNOWN-SAME: {{^}} "-L[[SYSROOT]]/usr/lib/../lib64"
+/// /usr/x86_64-linux-gnu does not exist, so there is no /usr/lib/gcc/x86_64-linux-gnu/10/../../../../x86_64-linux-gnu/lib.
+/// -ccc-install-dir is not within sysroot. No bin/../lib.
+/// $sysroot/lib and $sysroot/usr/lib. Fallback when GCC installation is unavailable.
+// DEBIAN_X86_64_PER_TARGET_UNKNOWN-SAME: {{^}} "-L[[SYSROOT]]/lib"
+// DEBIAN_X86_64_PER_TARGET_UNKNOWN-SAME: {{^}} "-L[[SYSROOT]]/usr/lib"
+// DEBIAN_X86_64_PER_TARGET_UNKNOWN-SAME: "[[RESOURCE]]/lib/x86_64-unknown-linux-gnu/libclang_rt.builtins.a"
 
 /// Test -m32.
-/// FIXME -internal-isystem .*bin/../include/i386-linux-gnu/c++/v1 and -L[[PREFIX]]/bin/../lib/i386-linux-gnu are missing.
 // RUN: %clang -### %s --target=x86_64-linux-gnu -m32 --sysroot=%S/Inputs/debian_multiarch_tree \
 // RUN:   -ccc-install-dir %S/Inputs/debian_per_target_tree/usr/lib/llvm-14/bin -resource-dir=%S/Inputs/debian_per_target_tree/usr/lib/llvm-14/lib/clang/14.0.0 \
 // RUN:   --stdlib=libc++ --rtlib=compiler-rt 2>&1 | FileCheck %s --check-prefix=DEBIAN_X86_64_M32_PER_TARGET
 // DEBIAN_X86_64_M32_PER_TARGET:      "-resource-dir" "[[RESOURCE:[^"]+]]"
 // DEBIAN_X86_64_M32_PER_TARGET:      "-internal-isystem"
-// DEBIAN_X86_64_M32_PER_TARGET-SAME: {{^}} "[[PREFIX:[^"]+llvm-14]]/bin/../include/c++/v1"
+// DEBIAN_X86_64_M32_PER_TARGET-SAME: {{^}} "[[PREFIX:[^"]+llvm-14]]/bin/../include/i386-linux-gnu/c++/v1"
+// DEBIAN_X86_64_M32_PER_TARGET-SAME: {{^}} "-internal-isystem" "[[PREFIX]]/bin/../include/c++/v1"
 // DEBIAN_X86_64_M32_PER_TARGET-SAME: {{^}} "-internal-isystem" "[[RESOURCE]]/include"
 // DEBIAN_X86_64_M32_PER_TARGET-SAME: {{^}} "-internal-isystem" "[[SYSROOT:[^"]+]]/usr/local/include"
 // DEBIAN_X86_64_M32_PER_TARGET-SAME: {{^}} "-internal-isystem" "[[SYSROOT]]/usr/lib/gcc/x86_64-linux-gnu/10/../../../../x86_64-linux-gnu/include"
 
 // DEBIAN_X86_64_M32_PER_TARGET:      "-L
-// DEBIAN_X86_64_M32_PER_TARGET-SAME: {{^}}[[SYSROOT]]/usr/lib/gcc/x86_64-linux-gnu/10/32"
+// DEBIAN_X86_64_M32_PER_TARGET-SAME: {{^}}[[PREFIX]]/bin/../lib/i386-linux-gnu"
+// DEBIAN_X86_64_M32_PER_TARGET-SAME: {{^}} "-L[[SYSROOT]]/usr/lib/gcc/x86_64-linux-gnu/10/32"
 // DEBIAN_X86_64_M32_PER_TARGET-SAME: {{^}} "-L[[SYSROOT]]/usr/lib/gcc/x86_64-linux-gnu/10/../../../../lib32"
 // DEBIAN_X86_64_M32_PER_TARGET-SAME: {{^}} "-L[[SYSROOT]]/lib/i386-linux-gnu"
 // DEBIAN_X86_64_M32_PER_TARGET-SAME: {{^}} "-L[[SYSROOT]]/lib/../lib32"
@@ -199,6 +232,7 @@
 // DEBIAN_X86_64_M32_PER_TARGET-SAME: {{^}} "-L[[SYSROOT]]/usr/lib/../lib32"
 // DEBIAN_X86_64_M32_PER_TARGET-SAME: {{^}} "-L[[SYSROOT]]/lib"
 // DEBIAN_X86_64_M32_PER_TARGET-SAME: {{^}} "-L[[SYSROOT]]/usr/lib"
+// DEBIAN_X86_64_M32_PER_TARGET-SAME: "[[RESOURCE]]/lib/i386-linux-gnu/libclang_rt.builtins.a"
 
 /// LDSO_ARCH is i386 for all x86-32 variants.
 // RUN: %clang -### %s --target=i686-linux-musl --sysroot= \