diff --git a/.azure/pipelines/ci.yml b/.azure/pipelines/ci.yml
index a3cce2ea12ed9bc4c3815f3ec1ca83d4e03a2519..a7dc48c128922827ac248affab579b2e19229c3b 100644
--- a/.azure/pipelines/ci.yml
+++ b/.azure/pipelines/ci.yml
@@ -51,6 +51,8 @@ variables:
            /p:DotNetPublishUsingPipelines=$(_PublishUsingPipelines)
            /p:DotNetArtifactsCategory=$(_DotNetArtifactsCategory)
   # Do not log most Windows steps in official builds; this is the slowest job. Site extensions step always logs.
+  - name: WindowsArm64LogArgs
+    value: -ExcludeCIBinaryLog
   - name: Windows64LogArgs
     value: -ExcludeCIBinaryLog
   - name: Windows86LogArgs
@@ -59,12 +61,16 @@ variables:
     value: -ExcludeCIBinaryLog
   - name: WindowsInstallersLogArgs
     value: -ExcludeCIBinaryLog
+  - name: WindowsArm64InstallersLogArgs
+    value: -ExcludeCIBinaryLog
 - ${{ if or(eq(variables['System.TeamProject'], 'public'), in(variables['Build.Reason'], 'PullRequest')) }}:
   - name: _BuildArgs
     value: '/p:SkipTestBuild=true'
   - name: _PublishArgs
     value: ''
   # Write binary logs for all main Windows build steps except the x86 one in public and PR builds.
+  - name: WindowsArm64LogArgs
+    value: /bl:artifacts/log/Release/Build.arm64.binlog
   - name: Windows64LogArgs
     value: /bl:artifacts/log/Release/Build.x64.binlog
   - name: Windows86LogArgs
@@ -73,6 +79,8 @@ variables:
     value: /bl:artifacts/log/Release/Build.CodeSign.binlog
   - name: WindowsInstallersLogArgs
     value: /bl:artifacts/log/Release/Build.Installers.binlog
+  - name: WindowsArm64InstallersLogArgs
+    value: /bl:artifacts/log/Release/Build.Installers.Arm64.binlog
 - ${{ if ne(variables['System.TeamProject'], 'internal') }}:
   - name: _UseHelixOpenQueues
     value: 'true'
@@ -263,18 +271,6 @@ stages:
       jobName: Windows_arm64_build
       jobDisplayName: "Build: Windows ARM64"
       agentOs: Windows
-      buildArgs:
-        -arch arm64
-        -sign
-        -pack
-        -noBuildNodeJS
-        -noBuildJava
-        /p:DotNetSignType=$(_SignType)
-        /p:OnlyPackPlatformSpecificPackages=true
-        /p:AssetManifestFileName=aspnetcore-win-arm64.xml
-        $(_BuildArgs)
-        $(_PublishArgs)
-        $(_InternalRuntimeDownloadArgs)
       installNodeJs: false
       installJdk: false
       artifacts:
@@ -286,6 +282,47 @@ stages:
         path: artifacts/packages/
       - name: Windows_arm64_Installers
         path: artifacts/installers/
+      steps:
+      - script: ./build.cmd
+                -ci
+                -arch arm64
+                -sign
+                -pack
+                -noBuildJava
+                -noBuildNative
+                /p:DotNetSignType=$(_SignType)
+                /p:OnlyPackPlatformSpecificPackages=true
+                $(_BuildArgs)
+                $(_InternalRuntimeDownloadArgs)
+                $(WindowsArm64LogArgs)
+        displayName: Build ARM64
+
+      # Windows installers bundle for arm64
+      - script: ./build.cmd
+                -ci
+                -noBuildRepoTasks
+                -arch arm64
+                -sign
+                -buildInstallers
+                -noBuildNative
+                /p:DotNetSignType=$(_SignType)
+                /p:AssetManifestFileName=aspnetcore-win-arm64.xml
+                $(_BuildArgs)
+                $(_PublishArgs)
+                $(_InternalRuntimeDownloadArgs)
+                $(WindowsArm64InstallersLogArgs)
+        displayName: Build Arm64 Installers
+
+      # A few files must also go to the VS package feed.
+      - ${{ if and(ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest')) }}:
+        - task: NuGetCommand@2
+          displayName: Push Visual Studio packages
+          inputs:
+            command: push
+            packagesToPush: 'artifacts/packages/**/VS.Redist.Common.AspNetCore.*.nupkg'
+            nuGetFeedType: external
+            publishFeedCredentials: 'DevDiv - VS package feed'
+
 
   # Build MacOS
   - template: jobs/default-build.yml
diff --git a/build.ps1 b/build.ps1
index 96e5cb7bf07af83032b6b7ed7063a74a5b44e430..0d82c3b2657b3482eca64e3d3ab96ed13a1e0382 100644
--- a/build.ps1
+++ b/build.ps1
@@ -296,12 +296,11 @@ if ($BuildNodeJS) { $dotnetBuildArguments += "/p:BuildNodeJS=true" }
 # Don't bother with two builds if just one will build everything. Ignore super-weird cases like
 # "-Projects ... -NoBuildJava -NoBuildManaged -NoBuildNodeJS". An empty `./build.ps1` command will build both
 # managed and native projects.
-$performDesktopBuild = ($BuildInstallers -or $BuildNative) -and `
-    -not $Architecture.StartsWith("arm", [System.StringComparison]::OrdinalIgnoreCase)
+$performDesktopBuild = ($BuildInstallers -and $Architecture -ne "arm") -or `
+    ($BuildNative -and -not $Architecture.StartsWith("arm", [System.StringComparison]::OrdinalIgnoreCase))
 $performDotnetBuild = $BuildJava -or $BuildManaged -or $BuildNodeJS -or `
     ($All -and -not ($NoBuildJava -and $NoBuildManaged -and $NoBuildNodeJS)) -or `
     ($Projects -and -not ($BuildInstallers -or $specifiedBuildNative))
-
 $foundJdk = $false
 $javac = Get-Command javac -ErrorAction Ignore -CommandType Application
 $localJdkPath = "$PSScriptRoot\.tools\jdk\win-x64\"
diff --git a/eng/Build.props b/eng/Build.props
index f0cb8db0b8a0958fa4da2ffdaf72e1683443238e..497ba8f4f80a91085889213956b0748d625d1564 100644
--- a/eng/Build.props
+++ b/eng/Build.props
@@ -50,7 +50,7 @@
       </ItemGroup>
     </When>
     <Otherwise>
-      <ItemGroup Condition=" '$(BuildInstallers)' == 'true' AND '$(TargetOsName)' == 'win' ">
+      <ItemGroup Condition=" '$(BuildInstallers)' == 'true' AND '$(TargetOsName)' == 'win' AND ('$(TargetArchitecture)' == 'x86' OR '$(TargetArchitecture)' == 'x64')  ">
         <!-- Build the ANCM custom action -->
         <ProjectToBuild Include="$(RepoRoot)src\Installers\Windows\AspNetCoreModule-Setup\CustomAction\aspnetcoreCA.vcxproj" AdditionalProperties="Platform=x64" />
         <ProjectToBuild Include="$(RepoRoot)src\Installers\Windows\AspNetCoreModule-Setup\CustomAction\aspnetcoreCA.vcxproj" AdditionalProperties="Platform=Win32" />
@@ -64,6 +64,10 @@
         <!-- Build the targeting pack installers -->
         <ProjectToBuild Include="$(RepoRoot)src\Installers\Windows\TargetingPack\TargetingPack.wixproj" AdditionalProperties="Platform=x64" />
         <ProjectToBuild Include="$(RepoRoot)src\Installers\Windows\TargetingPack\TargetingPack.wixproj" AdditionalProperties="Platform=x86" />
+        <!-- This really shouldn't be here, but instead of harvesting from the intermediate/output directories, the targetting pack installer logic
+        harvests from a zip of the reference assemblies. Producing it in each leg ends up with multiple targeting packs
+        getting produced and the BAR will reject the build. Centralize building the targeting pack in the x86/x64 leg. -->
+        <ProjectToBuild Include="$(RepoRoot)src\Installers\Windows\TargetingPack\TargetingPack.wixproj" AdditionalProperties="Platform=arm64" />
 
         <!-- Build the SharedFramework installers -->
         <ProjectToBuild Include="$(RepoRoot)src\Installers\Windows\SharedFrameworkBundle\SharedFrameworkBundle.wixproj" AdditionalProperties="Platform=x64" />
@@ -77,6 +81,14 @@
         <ProjectToBuild Include="$(RepoRoot)src\Installers\Windows\WindowsHostingBundle\WindowsHostingBundle.wixproj" AdditionalProperties="Platform=x86" />
       </ItemGroup>
 
+      <ItemGroup Condition=" '$(BuildInstallers)' == 'true' AND '$(TargetOsName)' == 'win' AND '$(TargetArchitecture)' == 'arm64' ">
+        <!-- We don't build the bundle here because we'd have to bundle the x86 installer which gets built in a different leg.
+        Instead we only provide the ARM64 MSI-->
+
+        <!-- Build the SharedFramework wixlib -->
+        <ProjectToBuild Include="$(RepoRoot)src\Installers\Windows\SharedFrameworkLib\SharedFrameworkLib.wixproj" AdditionalProperties="Platform=arm64" />
+      </ItemGroup>
+
       <ItemGroup Condition="'$(BuildInstallers)' == 'true' AND '$(TargetRuntimeIdentifier)' == 'linux-x64'">
         <ProjectToBuild Condition=" '$(LinuxInstallerType)' == 'deb' "
                         Include="$(RepoRoot)src\Installers\Debian\**\*.*proj" />
diff --git a/eng/targets/Wix.Common.props b/eng/targets/Wix.Common.props
index e6b1337fcba06b5c6a3740c1aeab6a282332cd11..9a29437eb2e597771c7f4c14fd32c4823691f360 100644
--- a/eng/targets/Wix.Common.props
+++ b/eng/targets/Wix.Common.props
@@ -3,8 +3,8 @@
 
   <PropertyGroup>
     <SchemaVersion>2.0</SchemaVersion>
-    <ProductVersion>3.11</ProductVersion>
-    <WixVersion>3.11.1</WixVersion>
+    <ProductVersion>3.14</ProductVersion>
+    <WixVersion>3.14.0-dotnet</WixVersion>
   </PropertyGroup>
 
   <PropertyGroup>
diff --git a/src/Installers/Windows/SharedFramework/Product.wxs b/src/Installers/Windows/SharedFramework/Product.wxs
index 2a71da323a2a3b4212d300266abde1248d1ea247..3375094918c06dea8240e40c92e679c5128f2250 100644
--- a/src/Installers/Windows/SharedFramework/Product.wxs
+++ b/src/Installers/Windows/SharedFramework/Product.wxs
@@ -2,7 +2,7 @@
 <Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
     <Product Id="$(var.ProductCode)" Name="$(var.ProductName)" Language="1033" Version="$(var.Version)"
              Manufacturer="Microsoft Corporation" UpgradeCode="$(var.UpgradeCode)">
-        <Package InstallerVersion="200" Compressed="yes" InstallScope="perMachine" />
+        <Package InstallerVersion="$(var.InstallerVersion)" Compressed="yes" InstallScope="perMachine" />
 
         <MajorUpgrade DowngradeErrorMessage="A newer version of [ProductName] is already installed." Schedule="afterInstallFinalize" />
         <Media Id="1" Cabinet="$(var.Cabinet)" CompressionLevel="high" EmbedCab="$(var.EmbedCab)" />
@@ -21,7 +21,7 @@
 
     <?if $(var.Platform)=x86?>
     <?define PFilesFolder=ProgramFilesFolder?>
-    <?elseif $(var.Platform)=x64?>
+    <?elseif $(var.Platform)=x64 or $(var.Platform)=arm64?>
     <?define PFilesFolder=ProgramFiles64Folder?>
     <?else?>
     <?error Invalid Platform ($(var.Platform))?>
diff --git a/src/Installers/Windows/SharedFramework/SharedFramework.wixproj b/src/Installers/Windows/SharedFramework/SharedFramework.wixproj
index edbb9f5bef01171e818bd40c61d594a41d75bbbf..6c87d7774704cf38a5e1b709f8469b2f49429aaf 100644
--- a/src/Installers/Windows/SharedFramework/SharedFramework.wixproj
+++ b/src/Installers/Windows/SharedFramework/SharedFramework.wixproj
@@ -61,12 +61,16 @@
   <!-- TODO: https://github.com/dotnet/aspnetcore/issues/6304. Harvest shared frameworks from a project reference -->
   <Target Name="ExtractIntermediateSharedFx" BeforeTargets="PrepareForBuild">
     <PropertyGroup>
+      <SharedFrameworkArm64HarvestRootPath Condition="'$(SharedFrameworkArm64HarvestRootPath)' == ''">$(InstallersOutputPath)</SharedFrameworkArm64HarvestRootPath>
       <SharedFrameworkX64HarvestRootPath Condition="'$(SharedFrameworkX64HarvestRootPath)' == ''">$(InstallersOutputPath)</SharedFrameworkX64HarvestRootPath>
       <SharedFrameworkX86HarvestRootPath Condition="'$(SharedFrameworkX86HarvestRootPath)' == ''">$(InstallersOutputPath)</SharedFrameworkX86HarvestRootPath>
+      <IntermediateArm64SharedFxZip>$(SharedFrameworkArm64HarvestRootPath)aspnetcore-runtime-internal-$(PackageVersion)-win-arm64.zip</IntermediateArm64SharedFxZip>
       <IntermediateX64SharedFxZip>$(SharedFrameworkX64HarvestRootPath)aspnetcore-runtime-internal-$(PackageVersion)-win-x64.zip</IntermediateX64SharedFxZip>
       <IntermediateX86SharedFxZip>$(SharedFrameworkX86HarvestRootPath)aspnetcore-runtime-internal-$(PackageVersion)-win-x86.zip</IntermediateX86SharedFxZip>
     </PropertyGroup>
 
+    <Unzip Condition="'$(Platform)' == 'arm64'"
+           SourceFiles="$(IntermediateArm64SharedFxZip)" DestinationFolder="$(HarvestSource)" />
     <Unzip Condition="'$(Platform)' == 'x64'"
            SourceFiles="$(IntermediateX64SharedFxZip)" DestinationFolder="$(HarvestSource)" />
     <Unzip Condition="'$(Platform)' == 'x86'"
diff --git a/src/Installers/Windows/SharedFrameworkBundle/Bundle.wxs b/src/Installers/Windows/SharedFrameworkBundle/Bundle.wxs
index 7f89a593091ab5970e3c16582e154f76d5e55e96..f54d1446b40cfb3cb8d1105f2a7f87ab1a5fe246 100644
--- a/src/Installers/Windows/SharedFrameworkBundle/Bundle.wxs
+++ b/src/Installers/Windows/SharedFrameworkBundle/Bundle.wxs
@@ -43,6 +43,8 @@
             <PackageGroupRef Id="PG_AspNetCoreSharedFramework_x86"/>
             <?elseif $(var.Platform)=x64?>
             <PackageGroupRef Id="PG_AspNetCoreSharedFramework_x64"/>
+            <?elseif $(var.Platform)=arm64?>
+            <PackageGroupRef Id="PG_AspNetCoreSharedFramework_arm64"/>
             <?endif?>
         </Chain>
     </Bundle>
diff --git a/src/Installers/Windows/SharedFrameworkBundle/SharedFrameworkBundle.wixproj b/src/Installers/Windows/SharedFrameworkBundle/SharedFrameworkBundle.wixproj
index 7aa16e58ec00be20ce2c1e40a7015a1f48b6737c..f9f285c8739418036fb356be9cb5189993ae14c6 100644
--- a/src/Installers/Windows/SharedFrameworkBundle/SharedFrameworkBundle.wixproj
+++ b/src/Installers/Windows/SharedFrameworkBundle/SharedFrameworkBundle.wixproj
@@ -29,20 +29,35 @@
     <Content Include="thm.xml" />
   </ItemGroup>
 
-  <ItemGroup>
-    <ProjectReference Include="..\SharedFrameworkLib\SharedFrameworkLib.wixproj" SetPlatform="Platform=x86">
-      <Name>SharedFrameworkLib</Name>
-      <Project>{5244BC49-2568-4701-80A6-EAB8950AB5FA}</Project>
-      <Private>True</Private>
-      <DoNotHarvest>True</DoNotHarvest>
-    </ProjectReference>
-    <ProjectReference Include="..\SharedFrameworkLib\SharedFrameworkLib.wixproj" SetPlatform="Platform=x64">
-      <Name>SharedFrameworkLib</Name>
-      <Project>{5244BC49-2568-4701-80A6-EAB8950AB5FA}</Project>
-      <Private>True</Private>
-      <DoNotHarvest>True</DoNotHarvest>
-    </ProjectReference>
-  </ItemGroup>
+  <Choose>
+    <When Condition="'$(Platform)' == 'arm64'">
+      <ItemGroup>
+        <ProjectReference Include="..\SharedFrameworkLib\SharedFrameworkLib.wixproj" SetPlatform="Platform=arm64">
+          <Name>SharedFrameworkLib</Name>
+          <Project>{5244BC49-2568-4701-80A6-EAB8950AB5FA}</Project>
+          <Private>True</Private>
+          <DoNotHarvest>True</DoNotHarvest>
+        </ProjectReference>
+      </ItemGroup>
+    </When>
+    <Otherwise>
+      <ItemGroup>
+        <ProjectReference Include="..\SharedFrameworkLib\SharedFrameworkLib.wixproj" SetPlatform="Platform=x86">
+          <Name>SharedFrameworkLib</Name>
+          <Project>{5244BC49-2568-4701-80A6-EAB8950AB5FA}</Project>
+          <Private>True</Private>
+          <DoNotHarvest>True</DoNotHarvest>
+        </ProjectReference>
+        <ProjectReference Include="..\SharedFrameworkLib\SharedFrameworkLib.wixproj" SetPlatform="Platform=x64">
+          <Name>SharedFrameworkLib</Name>
+          <Project>{5244BC49-2568-4701-80A6-EAB8950AB5FA}</Project>
+          <Private>True</Private>
+          <DoNotHarvest>True</DoNotHarvest>
+        </ProjectReference>
+      </ItemGroup>
+    </Otherwise>
+  </Choose>
+
 
   <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), Directory.Build.targets))\Directory.Build.targets" />
 
diff --git a/src/Installers/Windows/SharedFrameworkLib/Library.wxs b/src/Installers/Windows/SharedFrameworkLib/Library.wxs
index dde16acbd7ffa488ea355c513de00f5b7dcb7dc6..c30f743d0bb36d697d929211f8dc9d7d4b7e5149 100644
--- a/src/Installers/Windows/SharedFrameworkLib/Library.wxs
+++ b/src/Installers/Windows/SharedFrameworkLib/Library.wxs
@@ -16,6 +16,9 @@
             <?elseif $(var.Platform)=x64?>
             <?define SharedFrameworkInstallCondition=VersionNT64 AND (NOT OPT_NO_SHAREDFX)?>
             <?define DotNetHome=DOTNETHOME_X64?>
+            <?elseif $(var.Platform)=arm64?>
+            <?define SharedFrameworkInstallCondition=VersionNT64 AND (NOT OPT_NO_SHAREDFX)?>
+            <?define DotNetHome=DOTNETHOME_ARM64?>
             <?endif?>
 
             <MsiPackage Id="AspNetCoreSharedFramework_$(var.Platform)"
diff --git a/src/Installers/Windows/TargetingPack/Product.wxs b/src/Installers/Windows/TargetingPack/Product.wxs
index ce7bda6695ebd71836b798ca80dc68a9f1606aec..a43f6ab4e17272b90af1e9294163bff51438d4e9 100644
--- a/src/Installers/Windows/TargetingPack/Product.wxs
+++ b/src/Installers/Windows/TargetingPack/Product.wxs
@@ -2,7 +2,7 @@
 <Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
     <Product Id="$(var.ProductCode)" Name="$(var.ProductName)" Language="1033" Version="$(var.Version)"
              Manufacturer="Microsoft Corporation" UpgradeCode="$(var.UpgradeCode)">
-        <Package InstallerVersion="200" Compressed="yes" InstallScope="perMachine" />
+        <Package InstallerVersion="$(var.InstallerVersion)" Compressed="yes" InstallScope="perMachine" />
 
         <MajorUpgrade DowngradeErrorMessage="A newer version of [ProductName] is already installed." Schedule="afterInstallFinalize" />
         <Media Id="1" Cabinet="$(var.Cabinet)" CompressionLevel="high" EmbedCab="$(var.EmbedCab)" />
@@ -21,7 +21,7 @@
 
     <?if $(var.Platform)=x86?>
     <?define PFilesFolder=ProgramFilesFolder?>
-    <?elseif $(var.Platform)=x64?>
+    <?elseif $(var.Platform)=x64 or $(var.Platform)=arm64?>
     <?define PFilesFolder=ProgramFiles64Folder?>
     <?else?>
     <?error Invalid Platform ($(var.Platform))?>
diff --git a/src/Installers/Windows/Wix.targets b/src/Installers/Windows/Wix.targets
index ec321d4c41a6fd930031e66b422699edb22136ec..4112082782a11ef6c60f6e57656e646b11f9fd40 100644
--- a/src/Installers/Windows/Wix.targets
+++ b/src/Installers/Windows/Wix.targets
@@ -8,6 +8,11 @@
     <_FileRevisionVersion Condition=" '$(_FileRevisionVersion)' == '' ">42424</_FileRevisionVersion>
     <BundleVersion>$(AspNetCoreMajorVersion).$(AspNetCoreMinorVersion).$(AspNetCorePatchVersion).$(_FileRevisionVersion)</BundleVersion>
 
+    <!-- ARM64 MSIs require the installer version to be at least 500. -->
+    <!-- See: https://docs.microsoft.com/en-us/windows/win32/msi/64-bit-windows-installer-packages -->
+    <DefineConstants Condition=" '$(Platform)' == 'arm64' ">$(DefineConstants);InstallerVersion=500</DefineConstants>
+    <DefineConstants Condition=" '$(Platform)' != 'arm64' ">$(DefineConstants);InstallerVersion=200</DefineConstants>
+
     <DefineConstants>$(DefineConstants);MajorVersion=$(AspNetCoreMajorVersion)</DefineConstants>
     <DefineConstants>$(DefineConstants);MinorVersion=$(AspNetCoreMinorVersion)</DefineConstants>
     <DefineConstants>$(DefineConstants);Version=$(Version)</DefineConstants>