diff --git a/src/core/transport/chttp2/stream_encoder.c b/src/core/transport/chttp2/stream_encoder.c
index 07eeb0a474aab8960e1fe12dcac0e457b9ea7f35..8595a598793480487b6cdb2cd54bb69d00f5acd2 100644
--- a/src/core/transport/chttp2/stream_encoder.c
+++ b/src/core/transport/chttp2/stream_encoder.c
@@ -175,7 +175,7 @@ static gpr_uint8 *add_tiny_header_data(framer_state *st, int len) {
 
 static void add_elem(grpc_chttp2_hpack_compressor *c, grpc_mdelem *elem) {
   gpr_uint32 key_hash = elem->key->hash;
-  gpr_uint32 elem_hash = key_hash ^ elem->value->hash;
+  gpr_uint32 elem_hash = GRPC_MDSTR_KV_HASH(key_hash, elem->value->hash);
   gpr_uint32 new_index = c->tail_remote_index + c->table_elems + 1;
   gpr_uint32 elem_size = 32 + GPR_SLICE_LENGTH(elem->key->slice) +
                          GPR_SLICE_LENGTH(elem->value->slice);
@@ -354,7 +354,7 @@ static gpr_uint32 dynidx(grpc_chttp2_hpack_compressor *c, gpr_uint32 index) {
 static void hpack_enc(grpc_chttp2_hpack_compressor *c, grpc_mdelem *elem,
                       framer_state *st) {
   gpr_uint32 key_hash = elem->key->hash;
-  gpr_uint32 elem_hash = key_hash ^ elem->value->hash;
+  gpr_uint32 elem_hash = GRPC_MDSTR_KV_HASH(key_hash, elem->value->hash);
   size_t decoder_space_usage;
   gpr_uint32 indices_key;
   int should_add_elem;
diff --git a/src/core/transport/metadata.c b/src/core/transport/metadata.c
index 1a869cfbc5966d5a12b0e9b7fd563f09176c4fc8..e8ab21667144ee1c4d1ce0b5c773a911ace04760 100644
--- a/src/core/transport/metadata.c
+++ b/src/core/transport/metadata.c
@@ -45,8 +45,6 @@
 #define INITIAL_STRTAB_CAPACITY 4
 #define INITIAL_MDTAB_CAPACITY 4
 
-#define KV_HASH(key, value) ((key)->hash ^ (value)->hash)
-
 typedef struct internal_string {
   /* must be byte compatible with grpc_mdstr */
   gpr_slice slice;
@@ -375,7 +373,7 @@ static void grow_mdtab(grpc_mdctx *ctx) {
 
   for (i = 0; i < ctx->mdtab_capacity; i++) {
     for (md = ctx->mdtab[i]; md; md = next) {
-      hash = KV_HASH(md->key, md->value);
+      hash = GRPC_MDSTR_KV_HASH(md->key->hash, md->value->hash);
       next = md->bucket_next;
       md->bucket_next = mdtab[hash % capacity];
       mdtab[hash % capacity] = md;
@@ -400,7 +398,7 @@ grpc_mdelem *grpc_mdelem_from_metadata_strings(grpc_mdctx *ctx,
                                                grpc_mdstr *mvalue) {
   internal_string *key = (internal_string *)mkey;
   internal_string *value = (internal_string *)mvalue;
-  gpr_uint32 hash = KV_HASH(mkey, mvalue);
+  gpr_uint32 hash = GRPC_MDSTR_KV_HASH(mkey->hash, mvalue->hash);
   internal_metadata *md;
 
   GPR_ASSERT(key->context == ctx);
diff --git a/src/core/transport/metadata.h b/src/core/transport/metadata.h
index 9fca3d4bd5ab5fb056a1b75e3c9dcc3cdff9094e..6c6dee5efd6cc4416ecf16b737551f98b1ca6823 100644
--- a/src/core/transport/metadata.h
+++ b/src/core/transport/metadata.h
@@ -35,6 +35,7 @@
 #define __GRPC_INTERNAL_TRANSPORT_METADATA_H__
 
 #include <grpc/support/slice.h>
+#include <grpc/support/useful.h>
 
 /* This file provides a mechanism for tracking metadata through the grpc stack.
    It's not intended for consumption outside of the library.
@@ -133,4 +134,6 @@ void grpc_mdelem_unref(grpc_mdelem *md);
    Does not promise that the returned string has no embedded nulls however. */
 const char *grpc_mdstr_as_c_string(grpc_mdstr *s);
 
+#define GRPC_MDSTR_KV_HASH(k_hash, v_hash) (GPR_ROTL((k_hash), 2) ^ (v_hash))
+
 #endif  /* __GRPC_INTERNAL_TRANSPORT_METADATA_H__ */