diff --git a/src/csharp/Grpc.Core/Grpc.Core.nuspec b/src/csharp/Grpc.Core/Grpc.Core.nuspec
index 49bccb050ef1595a35a6c3d9dd585e4729752b7e..0ada0049c2abe9d62ec841909e4a538541d1248e 100644
--- a/src/csharp/Grpc.Core/Grpc.Core.nuspec
+++ b/src/csharp/Grpc.Core/Grpc.Core.nuspec
@@ -16,7 +16,6 @@
     <tags>gRPC RPC Protocol HTTP/2</tags>
     <dependencies>
       <dependency id="Ix-Async" version="1.2.5" />
-      <dependency id="grpc.native.csharp" version="$version$" />
     </dependencies>
   </metadata>
   <files>
@@ -24,5 +23,12 @@
     <file src="bin/ReleaseSigned/Grpc.Core.pdb" target="lib/net45" />
     <file src="bin/ReleaseSigned/Grpc.Core.xml" target="lib/net45" />
     <file src="**\*.cs" target="src" />
+    <file src="Grpc.Core.targets" target="\build\net45\Grpc.Core.targets" />
+    <file src="windows_x86/grpc_csharp_ext.dll" target="/build/native/bin/windows_x86/grpc_csharp_ext.dll" />
+    <file src="windows_x64/grpc_csharp_ext.dll" target="/build/native/bin/windows_x64/grpc_csharp_ext.dll" />
+    <file src="linux_x86/libgrpc_csharp_ext.so" target="/build/native/bin/linux_x86/libgrpc_csharp_ext.so" />
+    <file src="linux_x64/libgrpc_csharp_ext.so" target="/build/native/bin/linux_x64/libgrpc_csharp_ext.so" />
+    <file src="macosx_x86/libgrpc_csharp_ext.dylib" target="/build/native/bin/macosx_x86/libgrpc_csharp_ext.dylib" />
+    <file src="macosx_x64/libgrpc_csharp_ext.dylib" target="/build/native/bin/macosx_x64/libgrpc_csharp_ext.dylib" />
   </files>
 </package>
diff --git a/src/csharp/grpc.native.csharp/grpc.native.csharp.targets b/src/csharp/Grpc.Core/Grpc.Core.targets
similarity index 100%
rename from src/csharp/grpc.native.csharp/grpc.native.csharp.targets
rename to src/csharp/Grpc.Core/Grpc.Core.targets
diff --git a/src/csharp/Grpc.Core/Internal/NativeExtension.cs b/src/csharp/Grpc.Core/Internal/NativeExtension.cs
index bff1e56582ac8d114bbb8832292bca36c83c6ce7..b45ba19c24d798518993ec0b9eeffc6bc47dd39c 100644
--- a/src/csharp/Grpc.Core/Internal/NativeExtension.cs
+++ b/src/csharp/Grpc.Core/Internal/NativeExtension.cs
@@ -32,7 +32,6 @@
 #endregion
 
 using System;
-using System.Globalization;
 using System.IO;
 using System.Reflection;
 
@@ -46,6 +45,7 @@ namespace Grpc.Core.Internal
     internal sealed class NativeExtension
     {
         const string NativeLibrariesDir = "nativelibs";
+        const string DnxStyleNativeLibrariesDir = "../../build/native/bin/";
 
         static readonly ILogger Logger = GrpcEnvironment.Logger.ForType<NativeExtension>();
         static readonly object staticLock = new object();
@@ -100,31 +100,48 @@ namespace Grpc.Core.Internal
             // TODO: allow customizing path to native extension (possibly through exposing a GrpcEnvironment property).
 
             var libraryFlavor = string.Format("{0}_{1}", GetPlatformString(), GetArchitectureString());
-            var fullPath = Path.Combine(Path.GetDirectoryName(GetAssemblyPath()),
-                NativeLibrariesDir, libraryFlavor, GetNativeLibraryFilename());
-            return new UnmanagedLibrary(fullPath);
+
+            var assemblyDirectory = Path.GetDirectoryName(GetAssemblyPath());
+
+            // With old-style VS projects, the native libraries get copied using a .targets rule to the build output folder
+            // alongside the compiled assembly.
+            var classicPath = Path.Combine(assemblyDirectory, NativeLibrariesDir, libraryFlavor, GetNativeLibraryFilename());
+
+            // DNX-style project.json projects will use Grpc.Core assembly directly in the location where it got restored
+            // by nuget. We locate the native libraries based on known structure of Grpc.Core nuget package.
+            var dnxStylePath = Path.Combine(assemblyDirectory, DnxStyleNativeLibrariesDir, libraryFlavor, GetNativeLibraryFilename());
+
+            return new UnmanagedLibrary(new string[] {classicPath, dnxStylePath});
         }
 
         private static string GetAssemblyPath()
         {
             var assembly = typeof(NativeExtension).GetTypeInfo().Assembly;
-
+#if DOTNET5_4
+            // Assembly.EscapedCodeBase does not exit under CoreCLR, but assemblies imported from a nuget package
+            // don't seem to be shadowed by DNX-based projects at all.
+            return assembly.Location;
+#else
             // If assembly is shadowed (e.g. in a webapp), EscapedCodeBase is pointing
             // to the original location of the assembly, and Location is pointing
             // to the shadow copy. We care about the original location because
             // the native dlls don't get shadowed.
+
             var escapedCodeBase = assembly.EscapedCodeBase;
             if (IsFileUri(escapedCodeBase))
             {
                 return new Uri(escapedCodeBase).LocalPath;
             }
             return assembly.Location;
+#endif
         }
 
+#if !DOTNET5_4
         private static bool IsFileUri(string uri)
         {
             return uri.ToLowerInvariant().StartsWith(Uri.UriSchemeFile);
         }
+#endif
 
         private static string GetPlatformString()
         {
diff --git a/src/csharp/Grpc.Core/Internal/UnmanagedLibrary.cs b/src/csharp/Grpc.Core/Internal/UnmanagedLibrary.cs
index 47308f8c9e783f0075bb02d060332b5a47b09850..5a807461015d1445448696a45b2a5bfc0bf1037e 100644
--- a/src/csharp/Grpc.Core/Internal/UnmanagedLibrary.cs
+++ b/src/csharp/Grpc.Core/Internal/UnmanagedLibrary.cs
@@ -32,8 +32,6 @@
 #endregion
 
 using System;
-using System.Collections.Concurrent;
-using System.Diagnostics;
 using System.IO;
 using System.Reflection;
 using System.Runtime.InteropServices;
@@ -63,14 +61,9 @@ namespace Grpc.Core.Internal
         readonly string libraryPath;
         readonly IntPtr handle;
 
-        public UnmanagedLibrary(string libraryPath)
+        public UnmanagedLibrary(string[] libraryPathAlternatives)
         {
-            this.libraryPath = GrpcPreconditions.CheckNotNull(libraryPath);
-
-            if (!File.Exists(this.libraryPath))
-            {
-                throw new FileNotFoundException("Error loading native library. File does not exist.", this.libraryPath);
-            }
+            this.libraryPath = FirstValidLibraryPath(libraryPathAlternatives);
 
             Logger.Debug("Attempting to load native library \"{0}\"", this.libraryPath);
 
@@ -139,6 +132,19 @@ namespace Grpc.Core.Internal
             throw new InvalidOperationException("Unsupported platform.");
         }
 
+        private static string FirstValidLibraryPath(string[] libraryPathAlternatives)
+        {
+            GrpcPreconditions.CheckArgument(libraryPathAlternatives.Length > 0, "libraryPathAlternatives cannot be empty.");
+            foreach (var path in libraryPathAlternatives)
+            {
+                if (File.Exists(path))
+                {
+                    return path;
+                }
+            }
+            throw new FileNotFoundException(String.Format("Error loading native library. Not found in any of the possible locations {0}", libraryPathAlternatives));
+        }
+
         private static class Windows
         {
             [DllImport("kernel32.dll")]
diff --git a/src/csharp/build_packages.bat b/src/csharp/build_packages.bat
index 7c42a6d3fc48792c20e2c3e48665a8f06dff31d3..9a60be26b6305c8db5fe3a2d6f956d86e94b5ebe 100644
--- a/src/csharp/build_packages.bat
+++ b/src/csharp/build_packages.bat
@@ -12,12 +12,12 @@ set NUGET=C:\nuget\nuget.exe
 
 @rem Collect the artifacts built by the previous build step if running on Jenkins
 @rem TODO(jtattermusch): is there a better way to do this?
-xcopy /Y /I ..\..\architecture=x86,language=csharp,platform=windows\artifacts\* grpc.native.csharp\windows_x86\
-xcopy /Y /I ..\..\architecture=x64,language=csharp,platform=windows\artifacts\* grpc.native.csharp\windows_x64\
-xcopy /Y /I ..\..\architecture=x86,language=csharp,platform=linux\artifacts\* grpc.native.csharp\linux_x86\
-xcopy /Y /I ..\..\architecture=x64,language=csharp,platform=linux\artifacts\* grpc.native.csharp\linux_x64\
-xcopy /Y /I ..\..\architecture=x86,language=csharp,platform=macos\artifacts\* grpc.native.csharp\macosx_x86\
-xcopy /Y /I ..\..\architecture=x64,language=csharp,platform=macos\artifacts\* grpc.native.csharp\macosx_x64\
+xcopy /Y /I ..\..\architecture=x86,language=csharp,platform=windows\artifacts\* Grpc.Core\windows_x86\
+xcopy /Y /I ..\..\architecture=x64,language=csharp,platform=windows\artifacts\* Grpc.Core\windows_x64\
+xcopy /Y /I ..\..\architecture=x86,language=csharp,platform=linux\artifacts\* Grpc.Core\linux_x86\
+xcopy /Y /I ..\..\architecture=x64,language=csharp,platform=linux\artifacts\* Grpc.Core\linux_x64\
+xcopy /Y /I ..\..\architecture=x86,language=csharp,platform=macos\artifacts\* Grpc.Core\macosx_x86\
+xcopy /Y /I ..\..\architecture=x64,language=csharp,platform=macos\artifacts\* Grpc.Core\macosx_x64\
 
 @rem Collect protoc artifacts built by the previous build step
 xcopy /Y /I ..\..\architecture=x86,language=protoc,platform=windows\artifacts\* protoc_plugins\windows_x86\
@@ -42,7 +42,6 @@ msbuild Grpc.sln /p:Configuration=ReleaseSigned || goto :error
 
 endlocal
 
-%NUGET% pack grpc.native.csharp\grpc.native.csharp.nuspec -Version %VERSION% || goto :error
 %NUGET% pack Grpc.Auth\Grpc.Auth.nuspec -Symbols -Version %VERSION% || goto :error
 %NUGET% pack Grpc.Core\Grpc.Core.nuspec -Symbols -Version %VERSION% || goto :error
 %NUGET% pack Grpc.HealthCheck\Grpc.HealthCheck.nuspec -Symbols -Version %VERSION_WITH_BETA% -Properties ProtobufVersion=%PROTOBUF_VERSION% || goto :error
diff --git a/src/csharp/grpc.native.csharp/README.md b/src/csharp/grpc.native.csharp/README.md
deleted file mode 100644
index 77f1cb9b1f25fb63dfc06d63402e767f8dab3a53..0000000000000000000000000000000000000000
--- a/src/csharp/grpc.native.csharp/README.md
+++ /dev/null
@@ -1,22 +0,0 @@
-gRPC Native Nuget package
-=========================
-
-Prerequisites
--------------
-
-NuGet binary
-
-Building the package
---------------------
-
-To build the native package, you need precompiled versions
-of grpc_csharp_ext library artifacts for Windows, Linux and Mac.
-In the normal gRPC release process, these are built by a Jenkins
-job and they are copied to the expected location before building
-the native nuget package is attempted.
-
-See tools/run_tests/build_artifacts.py for more details how
-precompiled artifacts are built.
-
-When building the native NuGet package, ignore the "Assembly outside lib folder"
-warnings (the DLLs are not assemblies, they are native libraries).
diff --git a/templates/src/csharp/build_packages.bat.template b/templates/src/csharp/build_packages.bat.template
index 32455683be8892dfbe2a4575ff0bac3a472363d5..3b445a8ac94323662a28813691ab352585fe752a 100644
--- a/templates/src/csharp/build_packages.bat.template
+++ b/templates/src/csharp/build_packages.bat.template
@@ -14,12 +14,12 @@
   
   @rem Collect the artifacts built by the previous build step if running on Jenkins
   @rem TODO(jtattermusch): is there a better way to do this?
-  xcopy /Y /I ..\..\architecture=x86,language=csharp,platform=windows\artifacts\* grpc.native.csharp\windows_x86${"\\"}
-  xcopy /Y /I ..\..\architecture=x64,language=csharp,platform=windows\artifacts\* grpc.native.csharp\windows_x64${"\\"}
-  xcopy /Y /I ..\..\architecture=x86,language=csharp,platform=linux\artifacts\* grpc.native.csharp\linux_x86${"\\"}
-  xcopy /Y /I ..\..\architecture=x64,language=csharp,platform=linux\artifacts\* grpc.native.csharp\linux_x64${"\\"}
-  xcopy /Y /I ..\..\architecture=x86,language=csharp,platform=macos\artifacts\* grpc.native.csharp\macosx_x86${"\\"}
-  xcopy /Y /I ..\..\architecture=x64,language=csharp,platform=macos\artifacts\* grpc.native.csharp\macosx_x64${"\\"}
+  xcopy /Y /I ..\..\architecture=x86,language=csharp,platform=windows\artifacts\* Grpc.Core\windows_x86${"\\"}
+  xcopy /Y /I ..\..\architecture=x64,language=csharp,platform=windows\artifacts\* Grpc.Core\windows_x64${"\\"}
+  xcopy /Y /I ..\..\architecture=x86,language=csharp,platform=linux\artifacts\* Grpc.Core\linux_x86${"\\"}
+  xcopy /Y /I ..\..\architecture=x64,language=csharp,platform=linux\artifacts\* Grpc.Core\linux_x64${"\\"}
+  xcopy /Y /I ..\..\architecture=x86,language=csharp,platform=macos\artifacts\* Grpc.Core\macosx_x86${"\\"}
+  xcopy /Y /I ..\..\architecture=x64,language=csharp,platform=macos\artifacts\* Grpc.Core\macosx_x64${"\\"}
   
   @rem Collect protoc artifacts built by the previous build step
   xcopy /Y /I ..\..\architecture=x86,language=protoc,platform=windows\artifacts\* protoc_plugins\windows_x86${"\\"}
@@ -44,7 +44,6 @@
   
   endlocal
   
-  %%NUGET% pack grpc.native.csharp\grpc.native.csharp.nuspec -Version %VERSION% || goto :error
   %%NUGET% pack Grpc.Auth\Grpc.Auth.nuspec -Symbols -Version %VERSION% || goto :error
   %%NUGET% pack Grpc.Core\Grpc.Core.nuspec -Symbols -Version %VERSION% || goto :error
   %%NUGET% pack Grpc.HealthCheck\Grpc.HealthCheck.nuspec -Symbols -Version %VERSION_WITH_BETA% -Properties ProtobufVersion=%PROTOBUF_VERSION% || goto :error