diff --git a/include/nss_dns.h b/include/nss_dns.h
new file mode 100644
index 0000000000..63b5853870
--- /dev/null
+++ b/include/nss_dns.h
@@ -0,0 +1,36 @@
+/* Internal routines for nss_dns.
+   Copyright (C) 2021 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#ifndef _NSS_DNS_H
+#define _NSS_DNS_H
+
+#include <nss.h>
+
+NSS_DECLARE_MODULE_FUNCTIONS (dns)
+
+libc_hidden_proto (_nss_dns_getcanonname_r)
+libc_hidden_proto (_nss_dns_gethostbyname3_r)
+libc_hidden_proto (_nss_dns_gethostbyname2_r)
+libc_hidden_proto (_nss_dns_gethostbyname_r)
+libc_hidden_proto (_nss_dns_gethostbyname4_r)
+libc_hidden_proto (_nss_dns_gethostbyaddr2_r)
+libc_hidden_proto (_nss_dns_gethostbyaddr_r)
+libc_hidden_proto (_nss_dns_getnetbyname_r)
+libc_hidden_proto (_nss_dns_getnetbyaddr_r)
+
+#endif
diff --git a/resolv/Makefile b/resolv/Makefile
index 4ba58dfa96..dd0a98c74f 100644
--- a/resolv/Makefile
+++ b/resolv/Makefile
@@ -31,6 +31,9 @@ routines := \
   dn_comp \
   dn_expand \
   dn_skipname \
+  dns-canon \
+  dns-host \
+  dns-network \
   herror \
   inet_addr \
   inet_ntop \
@@ -175,18 +178,6 @@ libanl-shared-only-routines += libanl-compat
 subdir-dirs = nss_dns
 vpath %.c nss_dns
 
-libnss_dns-routines := \
-  dns-canon \
-  dns-host \
-  dns-network \
-  # libnss_dns-routines
-
-libnss_dns-inhibit-o	= $(filter-out .os,$(object-suffixes))
-ifeq ($(build-static-nss),yes)
-routines                += $(libnss_dns-routines) $(libresolv-routines)
-static-only-routines    += $(libnss_dns-routines) $(libresolv-routines)
-endif
-
 ifeq ($(run-built-tests),yes)
 ifneq (no,$(PERL))
 tests-special += $(objpfx)mtrace-tst-leaks.out $(objpfx)mtrace-tst-leaks2.out \
diff --git a/resolv/Versions b/resolv/Versions
index f8b7700a1e..0e878d1421 100644
--- a/resolv/Versions
+++ b/resolv/Versions
@@ -124,6 +124,15 @@ libc {
     __resolv_context_get_preinit;
     __resolv_context_put;
     __resp;
+    _nss_dns_getcanonname_r;
+    _nss_dns_gethostbyaddr2_r;
+    _nss_dns_gethostbyaddr_r;
+    _nss_dns_gethostbyname2_r;
+    _nss_dns_gethostbyname3_r;
+    _nss_dns_gethostbyname4_r;
+    _nss_dns_gethostbyname_r;
+    _nss_dns_getnetbyaddr_r;
+    _nss_dns_getnetbyname_r;
   }
 }
 
@@ -215,15 +224,9 @@ libresolv {
 
 libnss_dns {
   GLIBC_PRIVATE {
-    _nss_dns_getcanonname_r;
-    _nss_dns_gethostbyaddr2_r;
-    _nss_dns_gethostbyaddr_r;
-    _nss_dns_gethostbyname2_r;
-    _nss_dns_gethostbyname3_r;
-    _nss_dns_gethostbyname4_r;
-    _nss_dns_gethostbyname_r;
-    _nss_dns_getnetbyaddr_r;
-    _nss_dns_getnetbyname_r;
+    # Keep a version node (with a synthesized local: * directive) so that
+    # __bss_* symbols are hidden on targets that need it.
+    __libnss_dns_version_placeholder;
   }
 }
 
diff --git a/resolv/nss_dns/dns-canon.c b/resolv/nss_dns/dns-canon.c
index c5718ce3ab..c892170abd 100644
--- a/resolv/nss_dns/dns-canon.c
+++ b/resolv/nss_dns/dns-canon.c
@@ -25,8 +25,7 @@
 #include <nsswitch.h>
 #include <resolv/resolv_context.h>
 #include <resolv/resolv-internal.h>
-
-NSS_DECLARE_MODULE_FUNCTIONS (dns)
+#include <nss_dns.h>
 
 #if PACKETSZ > 65536
 # define MAXPACKET	PACKETSZ
@@ -185,3 +184,4 @@ _nss_dns_getcanonname_r (const char *name, char *buffer, size_t buflen,
   __resolv_context_put (ctx);
   return status;
 }
+libc_hidden_def (_nss_dns_getcanonname_r)
diff --git a/resolv/nss_dns/dns-host.c b/resolv/nss_dns/dns-host.c
index d6a69a602a..7248ade18d 100644
--- a/resolv/nss_dns/dns-host.c
+++ b/resolv/nss_dns/dns-host.c
@@ -82,6 +82,7 @@
 
 #include "nsswitch.h"
 #include <arpa/nameser.h>
+#include <nss_dns.h>
 
 #include <resolv/resolv-internal.h>
 #include <resolv/resolv_context.h>
@@ -90,8 +91,6 @@
 #include <resolv/mapv4v6addr.h>
 #include <resolv/mapv4v6hostent.h>
 
-NSS_DECLARE_MODULE_FUNCTIONS (dns)
-
 #define RESOLVSORT
 
 #if PACKETSZ > 65536
@@ -169,6 +168,7 @@ _nss_dns_gethostbyname3_r (const char *name, int af, struct hostent *result,
   __resolv_context_put (ctx);
   return status;
 }
+libc_hidden_def (_nss_dns_gethostbyname3_r)
 
 static enum nss_status
 gethostbyname3_context (struct resolv_context *ctx,
@@ -283,7 +283,7 @@ gethostbyname3_context (struct resolv_context *ctx,
 static enum nss_status
 check_name (const char *name, int *h_errnop)
 {
-  if (res_hnok (name))
+  if (__libc_res_hnok (name))
     return NSS_STATUS_SUCCESS;
   *h_errnop = HOST_NOT_FOUND;
   return NSS_STATUS_NOTFOUND;
@@ -300,7 +300,7 @@ _nss_dns_gethostbyname2_r (const char *name, int af, struct hostent *result,
   return _nss_dns_gethostbyname3_r (name, af, result, buffer, buflen, errnop,
 				    h_errnop, NULL, NULL);
 }
-
+libc_hidden_def (_nss_dns_gethostbyname2_r)
 
 enum nss_status
 _nss_dns_gethostbyname_r (const char *name, struct hostent *result,
@@ -327,7 +327,7 @@ _nss_dns_gethostbyname_r (const char *name, struct hostent *result,
   __resolv_context_put (ctx);
   return status;
 }
-
+libc_hidden_def (_nss_dns_gethostbyname_r)
 
 enum nss_status
 _nss_dns_gethostbyname4_r (const char *name, struct gaih_addrtuple **pat,
@@ -419,15 +419,7 @@ _nss_dns_gethostbyname4_r (const char *name, struct gaih_addrtuple **pat,
   __resolv_context_put (ctx);
   return status;
 }
-
-
-extern enum nss_status _nss_dns_gethostbyaddr2_r (const void *addr,
-						  socklen_t len, int af,
-						  struct hostent *result,
-						  char *buffer, size_t buflen,
-						  int *errnop, int *h_errnop,
-						  int32_t *ttlp);
-hidden_proto (_nss_dns_gethostbyaddr2_r)
+libc_hidden_def (_nss_dns_gethostbyname4_r)
 
 enum nss_status
 _nss_dns_gethostbyaddr2_r (const void *addr, socklen_t len, int af,
@@ -568,7 +560,7 @@ _nss_dns_gethostbyaddr2_r (const void *addr, socklen_t len, int af,
   __resolv_context_put (ctx);
   return NSS_STATUS_SUCCESS;
 }
-hidden_def (_nss_dns_gethostbyaddr2_r)
+libc_hidden_def (_nss_dns_gethostbyaddr2_r)
 
 
 enum nss_status
@@ -579,6 +571,7 @@ _nss_dns_gethostbyaddr_r (const void *addr, socklen_t len, int af,
   return _nss_dns_gethostbyaddr2_r (addr, len, af, result, buffer, buflen,
 				    errnop, h_errnop, NULL);
 }
+libc_hidden_def (_nss_dns_gethostbyaddr_r)
 
 static void
 addrsort (struct resolv_context *ctx, char **ap, int num)
@@ -672,10 +665,10 @@ getanswer_r (struct resolv_context *ctx,
     {
     case T_A:
     case T_AAAA:
-      name_ok = res_hnok;
+      name_ok = __libc_res_hnok;
       break;
     case T_PTR:
-      name_ok = res_dnok;
+      name_ok = __libc_res_dnok;
       break;
     default:
       *errnop = ENOENT;
@@ -810,7 +803,8 @@ getanswer_r (struct resolv_context *ctx,
 
 	  if (ap >= &host_data->aliases[MAX_NR_ALIASES - 1])
 	    continue;
-	  n = dn_expand (answer->buf, end_of_message, cp, tbuf, sizeof tbuf);
+	  n = __libc_dn_expand (answer->buf, end_of_message, cp,
+				tbuf, sizeof tbuf);
 	  if (__glibc_unlikely (n < 0 || (*name_ok) (tbuf) == 0))
 	    {
 	      ++had_error;
@@ -848,8 +842,9 @@ getanswer_r (struct resolv_context *ctx,
 	  if (ttlp != NULL && ttl < *ttlp)
 	      *ttlp = ttl;
 
-	  n = dn_expand (answer->buf, end_of_message, cp, tbuf, sizeof tbuf);
-	  if (__glibc_unlikely (n < 0 || res_dnok (tbuf) == 0))
+	  n = __libc_dn_expand (answer->buf, end_of_message, cp,
+				tbuf, sizeof tbuf);
+	  if (__glibc_unlikely (n < 0 || __libc_res_dnok (tbuf) == 0))
 	    {
 	      ++had_error;
 	      continue;
@@ -881,7 +876,7 @@ getanswer_r (struct resolv_context *ctx,
       switch (type)
 	{
 	case T_PTR:
-	  if (__glibc_unlikely (strcasecmp (tname, bp) != 0))
+	  if (__glibc_unlikely (__strcasecmp (tname, bp) != 0))
 	    {
 	      cp += n;
 	      continue;			/* XXX - had_error++ ? */
@@ -897,7 +892,7 @@ getanswer_r (struct resolv_context *ctx,
 	      n = -1;
 	    }
 
-	  if (__glibc_unlikely (n < 0 || res_hnok (bp) == 0))
+	  if (__glibc_unlikely (n < 0 || __libc_res_hnok (bp) == 0))
 	    {
 	      ++had_error;
 	      break;
@@ -911,7 +906,7 @@ getanswer_r (struct resolv_context *ctx,
 	  return NSS_STATUS_SUCCESS;
 	case T_A:
 	case T_AAAA:
-	  if (__glibc_unlikely (strcasecmp (result->h_name, bp) != 0))
+	  if (__glibc_unlikely (__strcasecmp (result->h_name, bp) != 0))
 	    {
 	      cp += n;
 	      continue;			/* XXX - had_error++ ? */
@@ -1060,7 +1055,7 @@ gaih_getanswer_slice (const querybuf *answer, int anslen, const char *qname,
       *h_errnop = NO_RECOVERY;
       return NSS_STATUS_UNAVAIL;
     }
-  if (__glibc_unlikely (res_hnok (buffer) == 0))
+  if (__glibc_unlikely (__libc_res_hnok (buffer) == 0))
     {
       errno = EBADMSG;
       *errnop = EBADMSG;
@@ -1093,7 +1088,7 @@ gaih_getanswer_slice (const querybuf *answer, int anslen, const char *qname,
 
 	  n = -1;
 	}
-      if (__glibc_unlikely (n < 0 || res_hnok (buffer) == 0))
+      if (__glibc_unlikely (n < 0 || __libc_res_hnok (buffer) == 0))
 	{
 	  ++had_error;
 	  continue;
@@ -1142,8 +1137,9 @@ gaih_getanswer_slice (const querybuf *answer, int anslen, const char *qname,
 	  if (ttlp != NULL && ttl < *ttlp)
 	      *ttlp = ttl;
 
-	  n = dn_expand (answer->buf, end_of_message, cp, tbuf, sizeof tbuf);
-	  if (__glibc_unlikely (n < 0 || res_hnok (tbuf) == 0))
+	  n = __libc_dn_expand (answer->buf, end_of_message, cp,
+				tbuf, sizeof tbuf);
+	  if (__glibc_unlikely (n < 0 || __libc_res_hnok (tbuf) == 0))
 	    {
 	      ++had_error;
 	      continue;
diff --git a/resolv/nss_dns/dns-network.c b/resolv/nss_dns/dns-network.c
index 801313caec..74b78959c2 100644
--- a/resolv/nss_dns/dns-network.c
+++ b/resolv/nss_dns/dns-network.c
@@ -67,11 +67,10 @@
 #include "nsswitch.h"
 #include <arpa/inet.h>
 #include <arpa/nameser.h>
+#include <nss_dns.h>
 #include <resolv/resolv-internal.h>
 #include <resolv/resolv_context.h>
 
-NSS_DECLARE_MODULE_FUNCTIONS (dns)
-
 /* Maximum number of aliases we allow.  */
 #define MAX_NR_ALIASES	48
 
@@ -152,7 +151,7 @@ _nss_dns_getnetbyname_r (const char *name, struct netent *result,
   __resolv_context_put (ctx);
   return status;
 }
-
+libc_hidden_def (_nss_dns_getnetbyname_r)
 
 enum nss_status
 _nss_dns_getnetbyaddr_r (uint32_t net, int type, struct netent *result,
@@ -246,7 +245,7 @@ _nss_dns_getnetbyaddr_r (uint32_t net, int type, struct netent *result,
   __resolv_context_put (ctx);
   return status;
 }
-
+libc_hidden_def (_nss_dns_getnetbyaddr_r)
 
 static enum nss_status
 getanswer_r (const querybuf *answer, int anslen, struct netent *result,
@@ -347,7 +346,7 @@ getanswer_r (const querybuf *answer, int anslen, struct netent *result,
 	  n = -1;
 	}
 
-      if (n < 0 || res_dnok (bp) == 0)
+      if (n < 0 || __libc_res_dnok (bp) == 0)
 	break;
       cp += n;
 
@@ -381,7 +380,7 @@ getanswer_r (const querybuf *answer, int anslen, struct netent *result,
 	      n = -1;
 	    }
 
-	  if (n < 0 || !res_hnok (bp))
+	  if (n < 0 || !__libc_res_hnok (bp))
 	    {
 	      /* XXX What does this mean?  The original form from bind
 		 returns NULL. Incrementing cp has no effect in any case.
@@ -469,7 +468,7 @@ getanswer_r (const querybuf *answer, int anslen, struct netent *result,
 		    /* If we are out of digits now, there are two cases:
 		       1. We are done with digits and now see "in-addr.arpa".
 		       2. This is not the droid we are looking for.  */
-		    if (!isdigit (*p) && !strcasecmp (p, "in-addr.arpa"))
+		    if (!isdigit (*p) && !__strcasecmp (p, "in-addr.arpa"))
 		      {
 			result->n_net = val;
 			return NSS_STATUS_SUCCESS;
