get rid of dll_only in build.yaml (#25524)

diff --git a/build_autogenerated.yaml b/build_autogenerated.yaml
index 0c4a3ea..715b9cc 100644
--- a/build_autogenerated.yaml
+++ b/build_autogenerated.yaml
@@ -1419,7 +1419,6 @@
   - absl/container:flat_hash_set
   - absl/container:flat_hash_map
   baselib: true
-  dll: true
   generate_plugin_registry: true
   secure: true
 - name: grpc_csharp_ext
@@ -1434,7 +1433,6 @@
   - gpr
   - address_sorting
   - upb
-  dll: only
 - name: grpc_test_util
   build: private
   language: c
@@ -2098,7 +2096,6 @@
   - absl/container:inlined_vector
   - absl/container:flat_hash_map
   baselib: true
-  dll: true
   generate_plugin_registry: true
   secure: false
 - name: benchmark_helpers
@@ -2381,7 +2378,6 @@
   - address_sorting
   - upb
   baselib: true
-  dll: true
 - name: grpc++_alts
   build: all
   language: c++
@@ -2733,7 +2729,6 @@
   - address_sorting
   - upb
   baselib: true
-  dll: true
   secure: false
 - name: grpc_plugin_support
   build: protoc
diff --git a/templates/CMakeLists.txt.template b/templates/CMakeLists.txt.template
index 022f52b..7fe97ee 100644
--- a/templates/CMakeLists.txt.template
+++ b/templates/CMakeLists.txt.template
@@ -47,6 +47,13 @@
         ret.append(get_absl_dep(dep).replace("::", "_"))
     return ret
 
+  def is_shared_only_lib(lib_name):
+    """Returns True if only shared library should be generated."""
+    # grpc_csharp_ext is loaded by C# runtime and it
+    # only makes sense as a shared lib.
+    return lib_name in ['grpc_csharp_ext']
+
+
   def get_deps(target_dict):
     deps = []
     if target_dict.get('baselib', False) or target_dict['name'] == 'address_sorting':
@@ -516,7 +523,7 @@
   if(gRPC_BUILD_CODEGEN)
   % endif
   % endif
-  add_library(${lib.name}${' SHARED' if lib.get('dll', None) == 'only' else ''}
+  add_library(${lib.name}${' SHARED' if is_shared_only_lib(lib.name) else ''}
   % for src in lib.src:
   % if not proto_re.match(src):
     ${src}
diff --git a/templates/README.md b/templates/README.md
index 1f92a24..e573c81 100644
--- a/templates/README.md
+++ b/templates/README.md
@@ -117,13 +117,6 @@
 on the `"language"` tag. OpenSSL and zlib are for `"c"` libraries, while
 protobuf is for `"c++"` ones.
 
-## The `"dll"` tag
-
-Currently only used by cmake. "true" means the project will be
-built with both static and dynamic runtimes. "false" means it'll only be built
-with static runtime. "only" means it'll only be built with the dll runtime.
-
-
 # The template system
 
 We're currently using the [mako templates](http://www.makotemplates.org/)
diff --git a/tools/buildgen/extract_metadata_from_bazel_xml.py b/tools/buildgen/extract_metadata_from_bazel_xml.py
index 20f8486..e39d45d 100755
--- a/tools/buildgen/extract_metadata_from_bazel_xml.py
+++ b/tools/buildgen/extract_metadata_from_bazel_xml.py
@@ -645,14 +645,12 @@
         'build': 'all',
         'baselib': True,
         'secure': True,
-        'dll': True,
         'generate_plugin_registry': True
     },
     'grpc++': {
         'language': 'c++',
         'build': 'all',
         'baselib': True,
-        'dll': True
     },
     'grpc++_alts': {
         'language': 'c++',
@@ -672,20 +670,17 @@
         'build': 'all',
         'baselib': True,
         'secure': False,
-        'dll': True
     },
     # TODO(jtattermusch): do we need to set grpc_csharp_ext's LDFLAGS for wrapping memcpy in the same way as in build.yaml?
     'grpc_csharp_ext': {
         'language': 'c',
         'build': 'all',
-        'dll': 'only'
     },
     'grpc_unsecure': {
         'language': 'c',
         'build': 'all',
         'baselib': True,
         'secure': False,
-        'dll': True,
         'generate_plugin_registry': True
     },
     'grpcpp_channelz': {