diff --git a/api/client.go b/api/client.go
index 40bf0ce6bfe6ce2bb6a991591fd53094feb4d1c0..f56a4ca3ff432224e1bc4f0ffaddb60233cfd937 100644
--- a/api/client.go
+++ b/api/client.go
@@ -30,6 +30,7 @@ import (
 	"gitlab.com/xx_network/crypto/signature/rsa"
 	"gitlab.com/xx_network/primitives/id"
 	"gitlab.com/xx_network/primitives/ndf"
+	"gitlab.com/xx_network/primitives/region"
 	"math"
 	"sync"
 	"time"
@@ -586,6 +587,61 @@ func (c *Client) DeleteContact(partnerId *id.ID) error {
 	return nil
 }
 
+// SetProxiedBins updates the host pool filter that filters out gateways that
+// are not in one of the specified bins.
+func (c *Client) SetProxiedBins(binStrings []string) error {
+	// Convert each region string into a region.GeoBin and place in a map for
+	// easy lookup
+	bins := make(map[region.GeoBin]bool, len(binStrings))
+	for i, binStr := range binStrings {
+		bin, err := region.GetRegion(binStr)
+		if err != nil {
+			return errors.Errorf("failed to parse geographic bin #%d: %+v", i, err)
+		}
+
+		bins[bin] = true
+	}
+
+	// Create filter func
+	f := func(m map[id.ID]int, netDef *ndf.NetworkDefinition) map[id.ID]int {
+		prunedList := make(map[id.ID]int, len(m))
+		for gwID, i := range m {
+			if bins[netDef.Gateways[i].Bin] {
+				prunedList[gwID] = i
+			}
+		}
+		return prunedList
+	}
+
+	c.network.SetPoolFilter(f)
+
+	return nil
+}
+
+// GetPreferredBins returns the geographic bin or bins that the provided two
+// character country code is a part of.
+func (c *Client) GetPreferredBins(countryCode string) ([]string, error) {
+	// Get the bin that the country is in
+	bin, exists := region.GetCountryBin(countryCode)
+	if !exists {
+		return nil, errors.Errorf("failed to find geographic bin for country %q",
+			countryCode)
+	}
+
+	// Add bin to list of geographic bins
+	bins := []string{bin.String()}
+
+	// Add additional bins in special cases
+	switch bin {
+	case region.Africa:
+		bins = append(bins, region.WesternEurope.String())
+	case region.MiddleEast:
+		bins = append(bins, region.EasternEurope.String())
+	}
+
+	return bins, nil
+}
+
 // ----- Utility Functions -----
 // parseNDF parses the initial ndf string for the client. do not check the
 // signature, it is deprecated.
diff --git a/api/utilsInterfaces_test.go b/api/utilsInterfaces_test.go
index 1faabce01353d23af8665858b4561e8aeb856836..ad97286b779237335a1e9b14f2606266d97ad3cf 100644
--- a/api/utilsInterfaces_test.go
+++ b/api/utilsInterfaces_test.go
@@ -136,3 +136,4 @@ func (t *testNetworkManagerGeneric) RegisterAddressSizeNotification(string) (cha
 }
 
 func (t *testNetworkManagerGeneric) UnregisterAddressSizeNotification(string) {}
+func (t *testNetworkManagerGeneric) SetPoolFilter(gateway.Filter)             {}
diff --git a/bindings/client.go b/bindings/client.go
index 1995b1900f2d54568714acb674f92f44ee795e10..09e0c7b6a6fc9ca4b643cf7cad645b7c466cd393 100644
--- a/bindings/client.go
+++ b/bindings/client.go
@@ -8,6 +8,8 @@
 package bindings
 
 import (
+	"bytes"
+	"encoding/csv"
 	"errors"
 	"fmt"
 	jww "github.com/spf13/jwalterweatherman"
@@ -20,6 +22,7 @@ import (
 	"gitlab.com/elixxir/primitives/states"
 	"gitlab.com/xx_network/primitives/id"
 	"gitlab.com/xx_network/primitives/netTime"
+	"strings"
 	"sync"
 	"time"
 )
@@ -437,6 +440,43 @@ func (c *Client) DeleteContact(b []byte) error {
 	return c.api.DeleteContact(contactObj.c.ID)
 }
 
+// SetProxiedBins updates the host pool filter that filters out gateways that
+// are not in one of the specified bins. The provided bins should be CSV.
+func (c *Client) SetProxiedBins(binStringsCSV string) error {
+	// Convert CSV to slice of strings
+	all, err := csv.NewReader(strings.NewReader(binStringsCSV)).ReadAll()
+	if err != nil {
+		return err
+	}
+
+	binStrings := make([]string, 0, len(all[0]))
+	for _, a := range all {
+		binStrings = append(binStrings, a...)
+	}
+
+	return c.api.SetProxiedBins(binStrings)
+}
+
+// GetPreferredBins returns the geographic bin or bins that the provided two
+// character country code is a part of. The bins are returned as CSV.
+func (c *Client) GetPreferredBins(countryCode string) (string, error) {
+	bins, err := c.api.GetPreferredBins(countryCode)
+	if err != nil {
+		return "", err
+	}
+
+	// Convert the slice of bins to CSV
+	buff := bytes.NewBuffer(nil)
+	csvWriter := csv.NewWriter(buff)
+	err = csvWriter.Write(bins)
+	if err != nil {
+		return "", err
+	}
+	csvWriter.Flush()
+
+	return buff.String(), nil
+}
+
 /*
 // SearchWithHandler is a non-blocking search that also registers
 // a callback interface for user disovery events.
diff --git a/go.sum b/go.sum
index 44d8f5f29aeae9c7ec004adf4d87e08e9b5285f6..c43b70d9d28cbced5293c4eb732a4ddfca78395f 100644
--- a/go.sum
+++ b/go.sum
@@ -77,6 +77,7 @@ github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:W
 github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
 github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
 github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
+github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
 github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
 github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
 github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
@@ -87,6 +88,7 @@ github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw
 github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
 github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
 github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
 github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
 github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
 github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
@@ -244,6 +246,7 @@ github.com/zeebo/assert v0.0.0-20181109011804-10f827ce2ed6/go.mod h1:yssERNPivll
 github.com/zeebo/assert v1.1.0 h1:hU1L1vLTHsnO8x8c9KAR5GmM5QscxHg5RNU5z5qbUWY=
 github.com/zeebo/assert v1.1.0/go.mod h1:Pq9JiuJQpG8JLJdtkwrJESF0Foym2/D9XMU5ciN/wJ0=
 github.com/zeebo/blake3 v0.0.4/go.mod h1:YOZo8A49yNqM0X/Y+JmDUZshJWLt1laHsNSn5ny2i34=
+github.com/zeebo/blake3 v0.1.0/go.mod h1:YOZo8A49yNqM0X/Y+JmDUZshJWLt1laHsNSn5ny2i34=
 github.com/zeebo/blake3 v0.1.1 h1:Nbsts7DdKThRHHd+YNlqiGlRqGEF2bE2eXN+xQ1hsEs=
 github.com/zeebo/blake3 v0.1.1/go.mod h1:G9pM4qQwjRzF1/v7+vabMj/c5mWpGZ2Wzo3Eb4z0pb4=
 github.com/zeebo/pcg v0.0.0-20181207190024-3cdc6b625a05/go.mod h1:Gr+78ptB0MwXxm//LBaEvBiaXY7hXJ6KGe2V32X2F6E=
@@ -296,6 +299,7 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh
 golang.org/x/crypto v0.0.0-20200707235045-ab33eee955e0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
 golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
 golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
+golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
 golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
 golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2 h1:It14KIkyBFYkHkwZ7k45minvA9aorojkyjGk9KJ5B/w=
 golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
@@ -332,6 +336,7 @@ golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn
 golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
 golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
 golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
+golang.org/x/net v0.0.0-20201029221708-28c70e62bb1d/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
 golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
 golang.org/x/net v0.0.0-20210525063256-abc453219eb5 h1:wjuX4b5yYQnEQHzd+CBcrcC6OVR2J1CN6mUy0oSxIPo=
 golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
@@ -362,7 +367,9 @@ golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7w
 golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20200917073148-efd3b9a0ff20/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20201014080544-cc95f250f6bc/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20201029080932-201ba4db2418/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20210319071255-635bc2c9138d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20210423082822-04245dca01da h1:b3NXsE2LusjYGGjL5bxEVZZORm/YEFFrWFjR8eFrw/c=
@@ -373,6 +380,7 @@ golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
 golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
 golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M=
 golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
 golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
@@ -418,6 +426,7 @@ google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98
 google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
 google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
 google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
+google.golang.org/genproto v0.0.0-20201030142918-24207fddd1c3/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
 google.golang.org/genproto v0.0.0-20210105202744-fe13368bc0e1 h1:Zk6zlGXdtYdcY5TL+VrbTfmifvk3VvsXopCpszsHPBA=
 google.golang.org/genproto v0.0.0-20210105202744-fe13368bc0e1/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
 google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
@@ -429,6 +438,7 @@ google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8
 google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
 google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
 google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
+google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=
 google.golang.org/grpc v1.38.0 h1:/9BgsAsa5nWe26HqOlvlgJnqBuktYOLCgjCPqsa56W0=
 google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
 google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
@@ -448,6 +458,7 @@ gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLks
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
 gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
 gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
diff --git a/groupChat/utils_test.go b/groupChat/utils_test.go
index eac797af004142994c37598337b4b98d79299b75..bdf58edfa1a3e2070c2d6144411463a6740c97a0 100644
--- a/groupChat/utils_test.go
+++ b/groupChat/utils_test.go
@@ -290,6 +290,7 @@ func (tnm *testNetworkManager) RegisterAddressSizeNotification(string) (chan uin
 	return nil, nil
 }
 func (tnm *testNetworkManager) UnregisterAddressSizeNotification(string) {}
+func (tnm *testNetworkManager) SetPoolFilter(gateway.Filter)             {}
 
 func getNDF() *ndf.NetworkDefinition {
 	return &ndf.NetworkDefinition{
diff --git a/interfaces/networkManager.go b/interfaces/networkManager.go
index 710700144bc2641b0f3caf87c00b65879cc0cb1a..c3bc9f49d6994012f0f2cbc58ed0016b62180f59 100644
--- a/interfaces/networkManager.go
+++ b/interfaces/networkManager.go
@@ -44,6 +44,9 @@ type NetworkManager interface {
 	// UnregisterAddressSizeNotification stops broadcasting address space size
 	// updates on the channel with the specified tag.
 	UnregisterAddressSizeNotification(tag string)
+
+	// SetPoolFilter sets the filter used to filter gateway IDs.
+	SetPoolFilter(f gateway.Filter)
 }
 
 //for use in key exchange which needs to be callable inside of network
diff --git a/keyExchange/utils_test.go b/keyExchange/utils_test.go
index 876a16576bfd95871fca6e099fb77caff25f6c02..cb0518466f10c4737fcc2376ce38ddfaeb318225 100644
--- a/keyExchange/utils_test.go
+++ b/keyExchange/utils_test.go
@@ -119,6 +119,7 @@ func (t *testNetworkManagerGeneric) RegisterAddressSizeNotification(string) (cha
 }
 
 func (t *testNetworkManagerGeneric) UnregisterAddressSizeNotification(string) {}
+func (t *testNetworkManagerGeneric) SetPoolFilter(gateway.Filter)             {}
 
 func InitTestingContextGeneric(i interface{}) (*storage.Session, interfaces.NetworkManager, error) {
 	switch i.(type) {
@@ -238,6 +239,7 @@ func (t *testNetworkManagerFullExchange) RegisterAddressSizeNotification(string)
 }
 
 func (t *testNetworkManagerFullExchange) UnregisterAddressSizeNotification(string) {}
+func (t *testNetworkManagerFullExchange) SetPoolFilter(gateway.Filter)             {}
 
 func InitTestingContextFullExchange(i interface{}) (*storage.Session, *switchboard.Switchboard, interfaces.NetworkManager) {
 	switch i.(type) {
diff --git a/network/ephemeral/testutil.go b/network/ephemeral/testutil.go
index 92eb68c408a0ecee0071651b5660c922d731934d..3b443dfe3a85f8c85e92dd235b190e00171df3ef 100644
--- a/network/ephemeral/testutil.go
+++ b/network/ephemeral/testutil.go
@@ -94,6 +94,7 @@ func (t *testNetworkManager) RegisterAddressSizeNotification(string) (chan uint8
 }
 
 func (t *testNetworkManager) UnregisterAddressSizeNotification(string) {}
+func (t *testNetworkManager) SetPoolFilter(gateway.Filter)             {}
 
 func NewTestNetworkManager(i interface{}) interfaces.NetworkManager {
 	switch i.(type) {
diff --git a/network/gateway/hostPool.go b/network/gateway/hostPool.go
index 1447608bfcc825f5e1269b2941d617718461662d..c5ecac1b155ed0f1949ee15d2622e0ad764a83ae 100644
--- a/network/gateway/hostPool.go
+++ b/network/gateway/hostPool.go
@@ -41,6 +41,13 @@ type HostManager interface {
 	RemoveHost(hid *id.ID)
 }
 
+// Filter filters out IDs from the provided map based on criteria in the NDF.
+// The passed in map is a map of the NDF for easier acesss.  The map is ID -> index in the NDF
+// There is no multithreading, the filter function can either edit the passed map or make a new one 
+// and return it.  The general pattern is to loop through the map, then look up data about the node 
+// in the ndf to make a filtering decision, then add them to a new map if they are accepted. 
+type Filter func(map[id.ID]int, *ndf.NetworkDefinition) map[id.ID]int
+
 // HostPool Handles providing hosts to the Client
 type HostPool struct {
 	hostMap  map[id.ID]uint32 // map key to its index in the slice
@@ -56,6 +63,9 @@ type HostPool struct {
 	storage        *storage.Session
 	manager        HostManager
 	addGatewayChan chan network.NodeGateway
+
+	filterMux sync.Mutex
+	filter    Filter
 }
 
 // PoolParams Allows configuration of HostPool parameters
@@ -85,13 +95,15 @@ func DefaultPoolParams() PoolParams {
 }
 
 // Build and return new HostPool object
-func newHostPool(poolParams PoolParams, rng *fastRNG.StreamGenerator, ndf *ndf.NetworkDefinition, getter HostManager,
-	storage *storage.Session, addGateway chan network.NodeGateway) (*HostPool, error) {
+func newHostPool(poolParams PoolParams, rng *fastRNG.StreamGenerator,
+	netDef *ndf.NetworkDefinition, getter HostManager, storage *storage.Session,
+	addGateway chan network.NodeGateway) (*HostPool, error) {
 	var err error
 
 	// Determine size of HostPool
 	if poolParams.PoolSize == 0 {
-		poolParams.PoolSize, err = getPoolSize(uint32(len(ndf.Gateways)), poolParams.MaxPoolSize)
+		poolParams.PoolSize, err = getPoolSize(uint32(len(netDef.Gateways)),
+			poolParams.MaxPoolSize)
 		if err != nil {
 			return nil, err
 		}
@@ -102,10 +114,15 @@ func newHostPool(poolParams PoolParams, rng *fastRNG.StreamGenerator, ndf *ndf.N
 		hostMap:        make(map[id.ID]uint32),
 		hostList:       make([]*connect.Host, poolParams.PoolSize),
 		poolParams:     poolParams,
-		ndf:            ndf,
+		ndf:            netDef,
 		rng:            rng,
 		storage:        storage,
 		addGatewayChan: addGateway,
+
+		// Initialise the filter so it does not filter any IDs
+		filter: func(m map[id.ID]int, _ *ndf.NetworkDefinition) map[id.ID]int {
+			return m
+		},
 	}
 
 	// Propagate the NDF
@@ -138,7 +155,7 @@ func newHostPool(poolParams PoolParams, rng *fastRNG.StreamGenerator, ndf *ndf.N
 		}
 	}
 
-	jww.INFO.Printf("Initialized HostPool with size: %d/%d", poolParams.PoolSize, len(ndf.Gateways))
+	jww.INFO.Printf("Initialized HostPool with size: %d/%d", poolParams.PoolSize, len(netDef.Gateways))
 	return result, nil
 }
 
@@ -161,6 +178,22 @@ func (h *HostPool) UpdateNdf(ndf *ndf.NetworkDefinition) {
 	h.ndfMux.Unlock()
 }
 
+// SetFilter sets the filter used to filter gateways from the ID map.
+func (h *HostPool) SetFilter(f Filter) {
+	h.filterMux.Lock()
+	defer h.filterMux.Unlock()
+
+	h.filter = f
+}
+
+// getFilter returns the filter used to filter gateways from the ID map.
+func (h *HostPool) getFilter() Filter {
+	h.filterMux.Lock()
+	defer h.filterMux.Unlock()
+
+	return h.filter
+}
+
 // Obtain a random, unique list of Hosts of the given length from the HostPool
 func (h *HostPool) getAny(length uint32, excluded []*id.ID) []*connect.Host {
 	if length > h.poolParams.PoolSize {
@@ -370,6 +403,9 @@ func (h *HostPool) updateConns() error {
 		return errors.Errorf("Unable to convert new NDF to set: %+v", err)
 	}
 
+	// Filter out gateway IDs
+	newMap = h.getFilter()(newMap, h.ndf)
+
 	// Handle adding Gateways
 	for gwId, ndfIdx := range newMap {
 		if _, ok := h.ndfMap[gwId]; !ok {
diff --git a/network/gateway/hostpool_test.go b/network/gateway/hostpool_test.go
index f88bdf49a5c02e757781f3c452b9eef2759862bb..e06d49dab9f88673e8a1fea3c4a364e7697c4190 100644
--- a/network/gateway/hostpool_test.go
+++ b/network/gateway/hostpool_test.go
@@ -470,6 +470,9 @@ func TestHostPool_UpdateNdf(t *testing.T) {
 		hostMap:  make(map[id.ID]uint32),
 		ndf:      testNdf,
 		storage:  storage.InitTestingSession(t),
+		filter: func(m map[id.ID]int, _ *ndf.NetworkDefinition) map[id.ID]int {
+			return m
+		},
 	}
 
 	// Construct a new Ndf different from original one above
diff --git a/network/manager.go b/network/manager.go
index d480f4afe6c2b23da229c4c20b0b752c3e4d936f..5fcef26c34cac6d6193e840ccce5f87303d8446d 100644
--- a/network/manager.go
+++ b/network/manager.go
@@ -200,3 +200,8 @@ func (m *manager) RegisterAddressSizeNotification(tag string) (chan uint8, error
 func (m *manager) UnregisterAddressSizeNotification(tag string) {
 	m.addrSpace.UnregisterNotification(tag)
 }
+
+// SetPoolFilter sets the filter used to filter gateway IDs.
+func (m *manager) SetPoolFilter(f gateway.Filter) {
+	m.sender.SetFilter(f)
+}
diff --git a/single/manager_test.go b/single/manager_test.go
index 4d570c35e900e2f36d1ee77bb76a298e927f09a7..28c3c15d0b62029c7fc0280cd83b529dd05af3ef 100644
--- a/single/manager_test.go
+++ b/single/manager_test.go
@@ -352,6 +352,7 @@ func (tnm *testNetworkManager) RegisterAddressSizeNotification(string) (chan uin
 }
 
 func (tnm *testNetworkManager) UnregisterAddressSizeNotification(string) {}
+func (tnm *testNetworkManager) SetPoolFilter(gateway.Filter)             {}
 
 func getNDF() *ndf.NetworkDefinition {
 	return &ndf.NetworkDefinition{