diff --git a/policy/pa.go b/policy/pa.go
index ab17bd89d..0a71a962d 100644
--- a/policy/pa.go
+++ b/policy/pa.go
@@ -32,6 +32,9 @@ type AuthorityImpl struct {
 	domainBlocklist       map[string]bool
 	fqdnBlocklist         map[string]bool
 	wildcardFqdnBlocklist map[string]bool
+	whitelist             map[string]bool
+	lockdown              map[string]bool
+	ldPublicContacts      bool
 	ipPrefixBlocklist     []netip.Prefix
 	blocklistMu           sync.RWMutex
 
@@ -73,6 +76,10 @@ type blockedIdentsPolicy struct {
 	// AdminBlockedPrefixes is a list of IP address prefixes. All IP addresses
 	// contained within the prefix are blocked.
 	AdminBlockedPrefixes []string `yaml:"AdminBlockedPrefixes"`
+
+	Whitelist                   []string `yaml:"Whitelist"`
+	Lockdown                    []string `yaml:"Lockdown"`
+	LockdownAllowPublicContacts bool     `yaml:"LockdownAllowPublicContacts"`
 }
 
 // LoadIdentPolicyFile will load the given policy file, returning an error if it
@@ -144,11 +151,23 @@ func (pa *AuthorityImpl) processIdentPolicy(policy blockedIdentsPolicy) error {
 		prefixes = append(prefixes, prefix)
 	}
 
+	whiteMap := make(map[string]bool)
+	for _, v := range policy.Whitelist {
+		whiteMap[v] = true
+	}
+	lockMap := make(map[string]bool)
+	for _, v := range policy.Lockdown {
+		lockMap[v] = true
+	}
+
 	pa.blocklistMu.Lock()
 	pa.domainBlocklist = nameMap
 	pa.fqdnBlocklist = exactNameMap
 	pa.wildcardFqdnBlocklist = wildcardNameMap
 	pa.ipPrefixBlocklist = prefixes
+	pa.whitelist = whiteMap
+	pa.lockdown = lockMap
+	pa.ldPublicContacts = policy.LockdownAllowPublicContacts
 	pa.blocklistMu.Unlock()
 	return nil
 }
@@ -219,7 +238,7 @@ var (
 //   - exactly equal to an IANA registered TLD
 //
 // It does NOT ensure that the domain is absent from any PA blocked lists.
-func validNonWildcardDomain(domain string) error {
+func (pa *AuthorityImpl) ValidNonWildcardDomain(domain string, isContact bool) error {
 	if domain == "" {
 		return errEmptyIdentifier
 	}
@@ -252,7 +271,9 @@ func validNonWildcardDomain(domain string) error {
 		return errTooManyLabels
 	}
 	if len(labels) < 2 {
-		return errTooFewLabels
+		if (len(pa.lockdown) > 0 || len(pa.whitelist) > 0) && !pa.lockdown[domain] && !pa.whitelist[domain] {
+			return errTooFewLabels
+		}
 	}
 	for _, label := range labels {
 		// Check that this is a valid LDH Label: "A string consisting of ASCII
@@ -296,12 +317,17 @@ func validNonWildcardDomain(domain string) error {
 		}
 	}
 
-	// Names must end in an ICANN TLD, but they must not be equal to an ICANN TLD.
-	icannTLD, err := iana.ExtractSuffix(domain)
+	ok, err := pa.checkWhitelist(domain, isContact)
 	if err != nil {
-		return errNonPublic
+		return err
+	}
+	if ok {
+		return nil
 	}
-	if icannTLD == domain {
+
+	// Names must not be equal to an ICANN TLD.
+	icannTLD, err := iana.ExtractSuffix(domain)
+	if err == nil && icannTLD == domain {
 		return errICANNTLD
 	}
 
@@ -311,9 +337,9 @@ func validNonWildcardDomain(domain string) error {
 // ValidDomain checks that a domain is valid and that it doesn't contain any
 // invalid wildcard characters. It does NOT ensure that the domain is absent
 // from any PA blocked lists.
-func ValidDomain(domain string) error {
+func (pa *AuthorityImpl) ValidDomain(domain string) error {
 	if strings.Count(domain, "*") <= 0 {
-		return validNonWildcardDomain(domain)
+		return pa.ValidNonWildcardDomain(domain, false)
 	}
 
 	// Names containing more than one wildcard are invalid.
@@ -332,7 +358,7 @@ func ValidDomain(domain string) error {
 
 	// Names must end in an ICANN TLD, but they must not be equal to an ICANN TLD.
 	icannTLD, err := iana.ExtractSuffix(baseDomain)
-	if err != nil {
+	if err != nil && !pa.lockdown[baseDomain] && !pa.whitelist[baseDomain] {
 		return errNonPublic
 	}
 	// Names must have a non-wildcard label immediately adjacent to the ICANN
@@ -340,7 +366,7 @@ func ValidDomain(domain string) error {
 	if baseDomain == icannTLD {
 		return errICANNTLDWildcard
 	}
-	return validNonWildcardDomain(baseDomain)
+	return pa.ValidNonWildcardDomain(baseDomain, false)
 }
 
 // ValidIP checks that an IP address:
@@ -383,14 +409,14 @@ var forbiddenMailDomains = map[string]bool{
 // ValidEmail returns an error if the input doesn't parse as an email address,
 // the domain isn't a valid hostname in Preferred Name Syntax, or its on the
 // list of domains forbidden for mail (because they are often used in examples).
-func ValidEmail(address string) error {
+func (pa *AuthorityImpl) ValidEmail(address string) error {
 	email, err := mail.ParseAddress(address)
 	if err != nil {
 		return berrors.InvalidEmailError("unable to parse email address")
 	}
 	splitEmail := strings.SplitN(email.Address, "@", -1)
 	domain := strings.ToLower(splitEmail[len(splitEmail)-1])
-	err = validNonWildcardDomain(domain)
+	err = pa.ValidNonWildcardDomain(domain, true)
 	if err != nil {
 		return berrors.InvalidEmailError("contact email has invalid domain: %s", err)
 	}
@@ -432,7 +458,7 @@ func subError(ident identifier.ACMEIdentifier, err error) berrors.SubBoulderErro
 //
 // Precondition: all input identifier values must be in lowercase.
 func (pa *AuthorityImpl) WillingToIssue(idents identifier.ACMEIdentifiers) error {
-	err := WellFormedIdentifiers(idents)
+	err := pa.WellFormedIdentifiers(idents)
 	if err != nil {
 		return err
 	}
@@ -449,6 +475,10 @@ func (pa *AuthorityImpl) WillingToIssue(idents identifier.ACMEIdentifiers) error
 			// The base domain is the wildcard request with the `*.` prefix removed
 			baseDomain := strings.TrimPrefix(ident.Value, "*.")
 
+			if ok, _ := pa.checkWhitelist(ident.Value, false); ok {
+				return nil
+			}
+
 			// The base domain can't be in the wildcard exact blocklist
 			err = pa.checkWildcardBlocklist(baseDomain)
 			if err != nil {
@@ -497,12 +527,12 @@ func (pa *AuthorityImpl) WillingToIssue(idents identifier.ACMEIdentifiers) error
 //
 // If multiple identifiers are invalid, the error will contain suberrors
 // specific to each identifier.
-func WellFormedIdentifiers(idents identifier.ACMEIdentifiers) error {
+func (pa *AuthorityImpl) WellFormedIdentifiers(idents identifier.ACMEIdentifiers) error {
 	var subErrors []berrors.SubBoulderError
 	for _, ident := range idents {
 		switch ident.Type {
 		case identifier.TypeDNS:
-			err := ValidDomain(ident.Value)
+			err := pa.ValidDomain(ident.Value)
 			if err != nil {
 				subErrors = append(subErrors, subError(ident, err))
 			}
@@ -544,6 +574,34 @@ func combineSubErrors(subErrors []berrors.SubBoulderError) error {
 	return nil
 }
 
+func (pa *AuthorityImpl) checkWhitelist(domain string, isContact bool) (bool, error) {
+	pa.blocklistMu.RLock()
+	defer pa.blocklistMu.RUnlock()
+
+	if (pa.whitelist == nil) || (pa.lockdown == nil) {
+		return false, fmt.Errorf("Hostname policy not yet loaded.")
+	}
+
+	labels := strings.Split(domain, ".")
+	for i := range labels {
+		joined := strings.Join(labels[i:], ".")
+		if pa.whitelist[joined] || pa.lockdown[joined] {
+			return true, nil
+		}
+	}
+
+	if len(pa.lockdown) > 0 {
+		if isContact && pa.ldPublicContacts {
+			return false, nil
+		}
+		// In Lockdown mode, the domain MUST be in the list, so return an error if not found
+		return false, errPolicyForbidden
+	} else {
+		// In Whitelist mode, if the domain is not in the list, continue with the other checks
+		return false, nil
+	}
+}
+
 // checkWildcardBlocklist checks the wildcardExactBlocklist for a given domain.
 // If the domain is not present on the list nil is returned, otherwise
 // errPolicyForbidden is returned.
@@ -575,6 +633,9 @@ func (pa *AuthorityImpl) checkBlocklists(ident identifier.ACMEIdentifier) error
 		labels := strings.Split(ident.Value, ".")
 		for i := range labels {
 			joined := strings.Join(labels[i:], ".")
+			if pa.lockdown[joined] || pa.whitelist[joined] {
+				return nil
+			}
 			if pa.domainBlocklist[joined] {
 				return errPolicyForbidden
 			}
