diff --git a/test/core/util/port_posix.c b/test/core/util/port_posix.c
index 60537b49469cfb7c2681100f15d4f32684ada530..1cb4a8c05fd78a5d14d2036c8a0acd25eb6ec369 100644
--- a/test/core/util/port_posix.c
+++ b/test/core/util/port_posix.c
@@ -39,6 +39,7 @@
 
 #include <errno.h>
 #include <netinet/in.h>
+#include <stdbool.h>
 #include <stdio.h>
 #include <string.h>
 #include <sys/socket.h>
@@ -50,6 +51,8 @@
 #include <grpc/support/string_util.h>
 
 #include "src/core/lib/http/httpcli.h"
+#include "src/core/lib/iomgr/resolve_address.h"
+#include "src/core/lib/iomgr/sockaddr_utils.h"
 #include "src/core/lib/support/env.h"
 #include "test/core/util/port_server_client.h"
 
@@ -115,55 +118,68 @@ static void chose_port(int port) {
   chosen_ports[num_chosen_ports - 1] = port;
 }
 
-static int is_port_available(int *port, int is_tcp) {
-  const int proto = is_tcp ? IPPROTO_TCP : 0;
-  const int fd = socket(AF_INET, is_tcp ? SOCK_STREAM : SOCK_DGRAM, proto);
-  int one = 1;
-  struct sockaddr_in addr;
-  socklen_t alen = sizeof(addr);
-  int actual_port;
-
+static bool is_port_available(int *port, bool is_tcp) {
   GPR_ASSERT(*port >= 0);
   GPR_ASSERT(*port <= 65535);
-  if (fd < 0) {
-    gpr_log(GPR_ERROR, "socket() failed: %s", strerror(errno));
-    return 0;
-  }
 
-  /* Reuseaddr lets us start up a server immediately after it exits */
-  if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)) < 0) {
-    gpr_log(GPR_ERROR, "setsockopt() failed: %s", strerror(errno));
-    close(fd);
-    return 0;
-  }
+  /* For a port to be considered available, the kernel must support
+     at least one of (IPv6, IPv4), and the port must be available
+     on each supported family. */
+  bool got_socket = false;
+  for (int is_ipv6 = 1; is_ipv6 >= 0; is_ipv6--) {
+    const int fd = socket(is_ipv6 ? AF_INET6 : AF_INET,
+                          is_tcp ? SOCK_STREAM : SOCK_DGRAM,
+                          is_tcp ? IPPROTO_TCP : 0);
+    if (fd >= 0) {
+      got_socket = true;
+    } else {
+      continue;
+    }
 
-  /* Try binding to port */
-  addr.sin_family = AF_INET;
-  addr.sin_addr.s_addr = INADDR_ANY;
-  addr.sin_port = htons((uint16_t)*port);
-  if (bind(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
-    gpr_log(GPR_DEBUG, "bind(port=%d) failed: %s", *port, strerror(errno));
-    close(fd);
-    return 0;
-  }
+    /* Reuseaddr lets us start up a server immediately after it exits */
+    const int one = 1;
+    if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)) < 0) {
+      gpr_log(GPR_ERROR, "setsockopt() failed: %s", strerror(errno));
+      close(fd);
+      return false;
+    }
+
+    /* Try binding to port */
+    grpc_resolved_address addr;
+    if (is_ipv6) {
+      grpc_sockaddr_make_wildcard6(*port, &addr);  /* [::]:port */
+    } else {
+      grpc_sockaddr_make_wildcard4(*port, &addr);  /* 0.0.0.0:port */
+    }
+    if (bind(fd, (struct sockaddr *)addr.addr, (socklen_t)addr.len) < 0) {
+      gpr_log(GPR_DEBUG, "bind(port=%d) failed: %s", *port, strerror(errno));
+      close(fd);
+      return false;
+    }
+
+    /* Get the bound port number */
+    if (getsockname(fd, (struct sockaddr *)addr.addr,
+                    (socklen_t *)&addr.len) < 0) {
+      gpr_log(GPR_ERROR, "getsockname() failed: %s", strerror(errno));
+      close(fd);
+      return false;
+    }
+    GPR_ASSERT(addr.len <= sizeof(addr.addr));
+    const int actual_port = grpc_sockaddr_get_port(&addr);
+    GPR_ASSERT(actual_port > 0);
+    if (*port == 0) {
+      *port = actual_port;
+    } else {
+      GPR_ASSERT(*port == actual_port);
+    }
 
-  /* Get the bound port number */
-  if (getsockname(fd, (struct sockaddr *)&addr, &alen) < 0) {
-    gpr_log(GPR_ERROR, "getsockname() failed: %s", strerror(errno));
     close(fd);
-    return 0;
   }
-  GPR_ASSERT(alen <= sizeof(addr));
-  actual_port = ntohs(addr.sin_port);
-  GPR_ASSERT(actual_port > 0);
-  if (*port == 0) {
-    *port = actual_port;
-  } else {
-    GPR_ASSERT(*port == actual_port);
+  if (!got_socket) {
+    gpr_log(GPR_ERROR, "socket() failed: %s", strerror(errno));
+    return false;
   }
-
-  close(fd);
-  return 1;
+  return true;
 }
 
 int grpc_pick_unused_port(void) {
@@ -180,7 +196,7 @@ int grpc_pick_unused_port(void) {
      UDP ports and they are scarcer. */
 
   /* Type of port to first pick in next iteration */
-  int is_tcp = 1;
+  bool is_tcp = true;
   int trial = 0;
 
   char *env = gpr_getenv("GRPC_TEST_PORT_SERVER");