It turns out that the order of the --exclude and --include flags passed to aws s3 sync and aws s3 cp matters, so
aws s3 sync 's3://my-bucket' . --include '*' --exclude '*.png'
won't download anything but
aws s3 sync 's3://my-bucket' . --exclude '*' --include '*.png'