How can I force Mathematica to not symbolically evaluate a function used for NMaximize without redefining it?

You could wrap your function in a head that suspends evaluation.

ClearAll[suspend];
SetAttributes[suspend, HoldFirst];
suspend[expr_, {__?NumericQ}] := expr

With[{vars = {x}}, NMaximize[suspend[f[x], vars], vars]]

Somewhat like wigg0t's in that it uses the pattern-matching of the evaluation sequence, replaceIf[in, pat :> expr] replaces the input in by expr if in matches the pattern pat:

ClearAll[replaceIf];
replaceIf[in_, (Rule | RuleDelayed)[pat_, expr_]] /; MatchQ[in, pat] := expr;

Usage:

NMaximize[replaceIf[x, _?NumericQ :> f[x]], x]

A possible alternative is to use the fact that Equal does not evaluate to True or False if an argument is symbolic:

NMaximize[If[x == 0 || x != 0, f[x]], x]